wip: store, subscription, api refactor to clear properly

This commit is contained in:
Logan Allen 2020-05-08 23:51:18 -04:00
parent 8fc7d8cc69
commit 2494ed30aa
9 changed files with 145 additions and 104 deletions

View File

@ -50,7 +50,8 @@ export default class App extends React.Component {
}
render() {
const Channel = window.channel;
const channel = window.channel;
return (
<ThemeProvider theme={light}>
<Root>
@ -59,19 +60,19 @@ export default class App extends React.Component {
<div>
<Route exact path="/" component={Home} />
<Route path="/~chat" render={
p => <ChatApp ship={this.ship} channel={new Channel()} {...p} />
p => <ChatApp ship={this.ship} channel={channel} {...p} />
}
/>
<Route path="/~dojo" render={
p => <DojoApp ship={this.ship} channel={new Channel()} {...p} />
p => <DojoApp ship={this.ship} channel={channel} {...p} />
}
/>
<Route path="/~groups" render={
p => <GroupsApp ship={this.ship} channel={new Channel()} {...p} />
p => <GroupsApp ship={this.ship} channel={channel} {...p} />
}
/>
<Route path="/~link" render={
p => <LinksApp ship={this.ship} channel={new Channel()} {...p} />
p => <LinksApp ship={this.ship} channel={channel} {...p} />
}
/>
</div>

View File

@ -1,9 +1,9 @@
import React from 'react';
import { Route } from 'react-router-dom';
import api from './api';
import store from './store';
import subscription from './subscription';
import Api from './api';
import Store from './store';
import Subscription from './subscription';
import './css/custom.css';
@ -19,9 +19,17 @@ import { NewDmScreen } from './components/new-dm';
export default class ChatApp extends React.Component {
constructor(props) {
super(props);
this.store = new Store();
this.store.setStateHandler(this.setState.bind(this));
this.state = store.state;
this.totalUnreads = 0;
store.setStateHandler(this.setState.bind(this));
this.resetControllers();
}
resetControllers() {
this.api = null;
this.subscription = null;
}
componentDidMount() {
@ -29,20 +37,18 @@ export default class ChatApp extends React.Component {
// preload spinner asset
new Image().src = '/~chat/img/Spinner.png';
api.setAuthTokens(
{ ship: this.props.ship },
this.props.channel
);
this.store.clear();
let channel = new this.props.channel();
this.api = new Api(this.props.ship, channel);
subscription.start(this.props.channel);
this.subscription = new Subscription(this.store, this.api, channel);
this.subscription.start();
}
componentWillUnmount() {
this.props.channel.delete();
store.firstRoundSubscriptionComplete = false;
store.handleEvent({
data: { clear: true }
});
this.subscription.delete();
this.store.clear();
this.resetControllers();
}
render() {
@ -87,7 +93,7 @@ export default class ChatApp extends React.Component {
contacts={contacts}
invites={invites['/chat'] || {}}
unreads={unreads}
api={api}
api={this.api}
station={station}
{...props}
/>
@ -133,7 +139,7 @@ export default class ChatApp extends React.Component {
sidebarShown={state.sidebarShown}
>
<NewDmScreen
api={api}
api={this.api}
inbox={state.inbox || {}}
permissions={state.permissions || {}}
contacts={state.contacts || {}}
@ -159,7 +165,7 @@ export default class ChatApp extends React.Component {
sidebarShown={state.sidebarShown}
>
<NewScreen
api={api}
api={this.api}
inbox={state.inbox || {}}
permissions={state.permissions || {}}
contacts={state.contacts || {}}
@ -191,7 +197,7 @@ export default class ChatApp extends React.Component {
sidebarShown={state.sidebarShown}
>
<JoinScreen
api={api}
api={this.api}
inbox={state.inbox}
autoJoin={station}
chatSynced={state.chatSynced || {}}
@ -253,8 +259,8 @@ export default class ChatApp extends React.Component {
chatSynced={state.chatSynced}
station={station}
association={association}
api={api}
subscription={subscription}
api={this.api}
subscription={this.subscription}
read={mailbox.config.read}
length={mailbox.config.length}
envelopes={mailbox.envelopes}

View File

@ -2,9 +2,10 @@ import _ from 'lodash';
import { uuid } from '../../lib/util';
import store from './store';
class UrbitApi {
setAuthTokens(authTokens, channel) {
this.authTokens = authTokens;
export default class Api {
constructor(ship, channel) {
this.ship = ship;
this.channel = channel;
this.bindPaths = [];
@ -33,9 +34,10 @@ class UrbitApi {
accept: this.inviteAccept.bind(this),
decline: this.inviteDecline.bind(this)
};
}
bind(path, method, ship = this.authTokens.ship, app, success, fail, quit) {
bind(path, method, ship = this.ship, app, success, fail, quit) {
this.bindPaths = _.uniq([...this.bindPaths, path]);
window.subscriptionId = this.channel.subscribe(ship, app, path,
@ -256,5 +258,3 @@ class UrbitApi {
}
}
const api = new UrbitApi();
export default api;

View File

@ -7,7 +7,7 @@ import MetadataReducer from '../../reducers/metadata-update';
import LocalReducer from '../../reducers/local';
import S3Reducer from '../../reducers/s3';
class Store {
export default class Store {
constructor() {
this.state = this.initialState();
@ -45,6 +45,12 @@ class Store {
this.setState = setState;
}
clear() {
this.handleEvent({
data: { clear: true }
});
}
handleEvent(data) {
let json = data.data;
@ -66,5 +72,3 @@ class Store {
}
}
const store = new Store();
export default store;

View File

@ -1,34 +1,40 @@
import api from './api';
import store from './store';
export default class Subscription {
constructor(store, api, channel) {
this.store = store;
this.api = api;
this.channel = channel;
export class Subscription {
constructor() {
this.firstRoundSubscriptionComplete = false;
this.channel.setOnChannelError(this.onChannelError.bind(this));
this.firstRoundComplete = false;
}
start(channel) {
if (api.authTokens) {
this.firstRoundSubscription();
channel.setOnChannelError(this.onChannelError.bind(this));
start() {
if (api.ship) {
this.firstRound();
} else {
console.error('~~~ ERROR: Must set api.authTokens before operation ~~~');
console.error('~~~ ERROR: Must set api.ship before operation ~~~');
}
}
delete() {
this.channel.delete();
}
onChannelError(err) {
console.error('event source error: ', err);
console.log('initiating new channel');
this.firstRoundSubscriptionComplete = false;
this.firstRoundComplete = false;
setTimeout(2000, () => {
store.handleEvent({
data: { clear : true }
});
this.start();
});
}
subscribe(path, app) {
api.bind(path, 'PUT', api.authTokens.ship, app,
api.bind(path, 'PUT', api.ship, app,
this.handleEvent.bind(this),
(err) => {
console.log(err);
@ -39,7 +45,7 @@ export class Subscription {
});
}
firstRoundSubscription() {
firstRound() {
this.subscribe('/primary', 'chat-view');
}
@ -53,16 +59,16 @@ export class Subscription {
}
handleEvent(diff) {
if (!this.firstRoundSubscriptionComplete) {
this.firstRoundSubscriptionComplete = true;
this.secondRoundSubscriptions();
if (!this.firstRoundComplete) {
this.firstRoundComplete = true;
this.secondRound();
}
store.handleEvent(diff);
}
fetchMessages(start, end, path) {
console.log(start, end, path);
fetch(`/~chat/paginate/${start}/${end}${path}`)
fetch(`/chat-view/paginate/${start}/${end}${path}`)
.then(response => response.json())
.then((json) => {
store.handleEvent({
@ -72,5 +78,3 @@ export class Subscription {
}
}
const subscription = new Subscription();
export default subscription;

View File

@ -6,37 +6,43 @@ import { Popout } from './components/lib/icons/popout';
import { History } from './components/history';
import { Input } from './components/input';
import store from './store';
import api from './api';
import subscription from './subscription';
import Api from './api';
import Store from './store';
import Subscription from './subscription';
import './css/custom.css';
export default class DojoApp extends Component {
constructor(props) {
super(props);
this.store = new Store();
this.store.setStateHandler(this.setState.bind(this));
this.state = store.state;
store.setStateHandler(this.setState.bind(this));
this.resetControllers();
}
resetControllers() {
this.api = null;
this.subscription = null;
}
componentDidMount() {
window.title = 'OS1 - Dojo';
api.setAuthTokens(
{
ship: this.props.ship,
dojoId: 'soto-' + Math.random().toString(36).substring(2)
},
this.props.channel
);
let channel = new this.props.channel();
this.api = new Api(this.props.ship, channel);
this.subscription = new Subscription(this.store, this.api, channel);
this.subscription.start();
subscription.start(this.props.channel);
}
componentWillUnmount() {
this.props.channel.delete();
store.handleEvent({
data: { clear: true }
});
this.subscription.delete();
this.store.clear();
this.resetControllers();
}
render() {

View File

@ -1,13 +1,15 @@
import _ from 'lodash';
class UrbitApi {
setAuthTokens(authTokens, channel) {
this.authTokens = authTokens;
export default class Api {
constructor(ship, channel) {
this.ship = ship;
this.channel = channel;
this.bindPaths = [];
this.dojoId = 'soto-' + Math.random().toString(36).substring(2);
}
bind(path, method, ship = this.authTokens.ship, appl = 'dojo', success, fail) {
bind(path, method, ship = this.ship, appl = 'dojo', success, fail) {
this.bindPaths = _.uniq([...this.bindPaths, path]);
window.subscriptionId = this.channel.subscribe(ship, appl, path,
@ -29,9 +31,7 @@ class UrbitApi {
}
soto(data) {
return this.action('dojo', 'sole-action',
{ id: this.authTokens.dojoId, dat: data }
);
return this.action('dojo', 'sole-action', { id: this.dojoId, dat: data });
}
action(appl, mark, data) {
@ -47,5 +47,3 @@ class UrbitApi {
}
}
const api = new UrbitApi();
export default api;

View File

@ -1,13 +1,12 @@
import Share from './components/lib/sole';
import api from './api';
export const buffer = new Share();
export class Store {
export default class Store {
constructor() {
this.state = this.initialState();
this.sync = this.sync.bind(this);
this.print = this.print.bind(this);
this.buffer = new Share();
}
initialState() {
@ -51,7 +50,7 @@ export class Store {
case 'hop':
return this.setState({ cursor: dojoReply.hop });
case 'det':
buffer.receive(dojoReply.det);
this.buffer.receive(dojoReply.det);
return this.sync(dojoReply.det.ted);
case 'act':
switch (dojoReply.act) {
@ -67,7 +66,7 @@ export class Store {
}
doEdit(ted) {
const detSend = buffer.transmit(ted);
const detSend = this.buffer.transmit(ted);
this.sync(ted);
return api.soto({ det: detSend });
}
@ -80,8 +79,8 @@ export class Store {
sync(ted) {
return this.setState({
input: buffer.buf,
cursor: buffer.transpose(ted, this.state.cursor)
input: this.buffer.buf,
cursor: this.buffer.transpose(ted, this.state.cursor)
});
}
@ -90,5 +89,3 @@ export class Store {
}
}
const store = new Store();
export default store;

View File

@ -1,34 +1,59 @@
import api from './api';
import store from './store';
export class Subscription {
export default class Subscription {
constructor(store, api, channel) {
this.store = store;
this.api = api;
this.channel = channel;
this.channel.setOnChannelError(this.onChannelError.bind(this));
this.firstRoundComplete = false;
}
start() {
if (api.authTokens) {
this.initializesoto();
if (api.ship) {
this.firstRound();
} else {
console.error('~~~ ERROR: Must set api.authTokens before operation ~~~');
console.error('~~~ ERROR: Must set api.ship before operation ~~~');
}
}
initializesoto() {
api.bind('/sole/' + api.authTokens.dojoId,
'PUT', api.authTokens.ship, 'dojo',
delete() {
this.channel.delete();
}
onChannelError(err) {
console.error('event source error: ', err);
console.log('initiating new channel');
this.firstRoundComplete = false;
setTimeout(2000, () => {
store.handleEvent({
data: { clear : true }
});
this.start();
});
}
subscribe(path, app) {
api.bind(path, 'PUT', api.ship, app,
this.handleEvent.bind(this),
this.handleError.bind(this));
(err) => {
console.log(err);
this.subscribe(path, app);
},
() => {
this.subscribe(path, app);
});
}
firstRound() {
this.subsribe('/sole/' + api.dojoId, 'dojo');
}
handleEvent(diff) {
store.handleEvent(diff);
}
handleError(err) {
console.error(err);
api.bind('/sole/' + api.authTokens.dojoId,
'PUT', api.authTokens.ship, 'dojo',
this.handleEvent.bind(this),
this.handleError.bind(this));
}
}
const subscription = new Subscription();
export default subscription;