Merge pull request #2616 from urbit/two-round

chat-js: improve subscription speed by doing two rounds of subscriptions and no longer subscribing to groups
This commit is contained in:
ixv 2020-03-30 17:48:39 -07:00 committed by GitHub
commit 8f1655171d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 52 additions and 189 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -224,7 +224,7 @@ export class ChatScreen extends Component {
); );
}); });
let group = Array.from(props.group.values()); let group = Array.from(props.permission.who.values());
const isinPopout = props.popout ? "popout/" : ""; const isinPopout = props.popout ? "popout/" : "";
@ -301,7 +301,6 @@ export class ChatScreen extends Component {
station={props.station} station={props.station}
owner={deSig(props.match.params.ship)} owner={deSig(props.match.params.ship)}
ownerContact={ownerContact} ownerContact={ownerContact}
permissions={props.permissions}
envelopes={props.envelopes} envelopes={props.envelopes}
contacts={props.contacts} contacts={props.contacts}
placeholder="Message..." placeholder="Message..."

View File

@ -422,36 +422,7 @@ export class ChatInput extends Component {
}); });
} }
readOnlyRender() { render() {
const { props } = this;
let color = !!props.ownerContact
? uxToHex(props.ownerContact.color) : '000000';
let sigilClass = !!props.ownerContact
? "" : "mix-blend-diff";
return (
<div className="pa3 cf flex black bt b--gray4 o-50">
<div className="fl" style={{
marginTop: 4,
flexBasis: 24,
height: 24
}}>
<Sigil
ship={window.ship}
size={24}
color={`#${color}`}
classes={sigilClass}
/>
</div>
<div className="fr h-100 flex" style={{ flexGrow: 1, height: 28, paddingTop: 6, resize: "none" }}>
<p className="pl3">This chat is read only and you cannot post.</p>
</div>
</div>
);
}
writeAccessRender() {
const { props, state } = this; const { props, state } = this;
let color = !!props.ownerContact let color = !!props.ownerContact
@ -505,29 +476,4 @@ export class ChatInput extends Component {
</div> </div>
); );
} }
render() {
const { props, state } = this;
let writePermission = props.permissions[`/chat${props.station}/write`];
if (writePermission) {
if (writePermission.kind === 'black') {
// black
if (writePermission.who.has(window.ship)) {
return this.readOnlyRender();
} else {
return this.writeAccessRender();
}
} else if (writePermission.kind === 'white') {
// white
if (writePermission.who.has(window.ship)) {
return this.writeAccessRender();
} else {
return this.readOnlyRender();
}
}
} else {
return this.writeAccessRender();
}
}
} }

View File

@ -49,6 +49,7 @@ export class InviteSearch extends Component {
let peers = [], let peers = [],
peerSet = new Set(), peerSet = new Set(),
contacts = new Map; contacts = new Map;
Object.keys(this.props.groups).map(group => { Object.keys(this.props.groups).map(group => {
if (this.props.groups[group].size > 0) { if (this.props.groups[group].size > 0) {
let groupEntries = this.props.groups[group].values(); let groupEntries = this.props.groups[group].values();
@ -56,6 +57,7 @@ export class InviteSearch extends Component {
peerSet.add(member); peerSet.add(member);
} }
} }
if (this.props.contacts[group]) { if (this.props.contacts[group]) {
let groupEntries = this.props.groups[group].values(); let groupEntries = this.props.groups[group].values();
for (let member of groupEntries) { for (let member of groupEntries) {

View File

@ -216,6 +216,11 @@ export class NewScreen extends Component {
); );
} }
let groups = {};
Object.keys(props.permissions).forEach((pem) => {
groups[pem] = props.permissions[pem].who;
});
return ( return (
<div <div
className={ className={
@ -259,7 +264,7 @@ export class NewScreen extends Component {
Selected groups or ships will be able to post to chat Selected groups or ships will be able to post to chat
</p> </p>
<InviteSearch <InviteSearch
groups={props.groups} groups={groups}
contacts={props.contacts} contacts={props.contacts}
associations={props.associations} associations={props.associations}
groupResults={true} groupResults={true}

View File

@ -99,7 +99,7 @@ export class Root extends Component {
<NewScreen <NewScreen
api={api} api={api}
inbox={state.inbox || {}} inbox={state.inbox || {}}
groups={state.groups || {}} permissions={state.permissions || {}}
contacts={state.contacts || {}} contacts={state.contacts || {}}
associations={associations.contacts} associations={associations.contacts}
{...props} {...props}
@ -119,7 +119,6 @@ export class Root extends Component {
station = '/~' + station; station = '/~' + station;
} }
return ( return (
<Skeleton <Skeleton
spinner={state.spinner} spinner={state.spinner}
@ -168,8 +167,11 @@ export class Root extends Component {
let association = let association =
station in associations["chat"] ? associations.chat[station] : {}; station in associations["chat"] ? associations.chat[station] : {};
let permission =
let group = state.groups[station] || new Set([]); station in state.permissions ? state.permissions[station] : {
who: new Set([]),
kind: 'white'
};
let popout = props.match.url.includes("/popout/"); let popout = props.match.url.includes("/popout/");
return ( return (
@ -190,9 +192,8 @@ export class Root extends Component {
length={mailbox.config.length} length={mailbox.config.length}
envelopes={mailbox.envelopes} envelopes={mailbox.envelopes}
inbox={state.inbox} inbox={state.inbox}
group={group}
contacts={roomContacts} contacts={roomContacts}
permissions={state.permissions} permission={permission}
pendingMessages={state.pendingMessages} pendingMessages={state.pendingMessages}
popout={popout} popout={popout}
sidebarShown={state.sidebarShown} sidebarShown={state.sidebarShown}
@ -255,7 +256,6 @@ export class Root extends Component {
if (sig) { if (sig) {
station = '/~' + station; station = '/~' + station;
} }
let group = state.groups[station] || new Set([]);
let popout = props.match.url.includes("/popout/"); let popout = props.match.url.includes("/popout/");
@ -280,12 +280,11 @@ export class Root extends Component {
station={station} station={station}
association={association} association={association}
permission={permission} permission={permission}
groups={state.groups || {}} permissions={state.permissions || {}}
contacts={state.contacts || {}} contacts={state.contacts || {}}
associations={associations.contacts} associations={associations.contacts}
api={api} api={api}
station={station} station={station}
group={group}
inbox={state.inbox} inbox={state.inbox}
popout={popout} popout={popout}
sidebarShown={state.sidebarShown} sidebarShown={state.sidebarShown}

View File

@ -223,7 +223,7 @@ export class SettingsScreen extends Component {
group to add this chat to. group to add this chat to.
</p> </p>
<InviteSearch <InviteSearch
groups={props.groups} permissions={props.permissions}
contacts={props.contacts} contacts={props.contacts}
associations={props.associations} associations={props.associations}
groupResults={true} groupResults={true}
@ -340,7 +340,7 @@ export class SettingsScreen extends Component {
const { props, state } = this; const { props, state } = this;
const isinPopout = this.props.popout ? "popout/" : ""; const isinPopout = this.props.popout ? "popout/" : "";
let writeGroup = Array.from(props.group.values()); let permission = Array.from(props.permission.who.values());
if (!!state.isLoading) { if (!!state.isLoading) {
let text = state.loadingText || 'Working...'; let text = state.loadingText || 'Working...';
@ -378,7 +378,7 @@ export class SettingsScreen extends Component {
<ChatTabBar <ChatTabBar
{...props} {...props}
station={props.station} station={props.station}
numPeers={writeGroup.length} numPeers={permission.length}
host={props.match.params.ship} host={props.match.params.ship}
api={props.api} api={props.api}
/> />
@ -423,7 +423,7 @@ export class SettingsScreen extends Component {
<ChatTabBar <ChatTabBar
{...props} {...props}
station={props.station} station={props.station}
numPeers={writeGroup.length} numPeers={permission.length}
isOwner={deSig(props.match.params.ship) === window.ship} isOwner={deSig(props.match.params.ship) === window.ship}
popout={this.props.popout} popout={this.props.popout}
/> />

View File

@ -1,65 +0,0 @@
import _ from 'lodash';
export class GroupUpdateReducer {
reduce(json, state) {
let data = _.get(json, 'group-update', false);
if (data) {
this.add(data, state);
this.remove(data, state);
this.bundle(data, state);
this.unbundle(data, state);
this.keys(data, state);
this.path(data, state);
}
}
add(json, state) {
let data = _.get(json, 'add', false);
if (data) {
for (let member of data.members) {
state.groups[data.path].add(member);
}
}
}
remove(json, state) {
let data = _.get(json, 'remove', false);
if (data) {
for (let member of data.members) {
state.groups[data.path].delete(member);
}
}
}
bundle(json, state) {
let data = _.get(json, 'bundle', false);
if (data) {
state.groups[data.path] = new Set();
}
}
unbundle(json, state) {
let data = _.get(json, 'unbundle', false);
if (data) {
delete state.groups[data.path];
}
}
keys(json, state) {
let data = _.get(json, 'keys', false);
if (data) {
state.groupKeys = new Set(data.keys);
}
}
path(json, state) {
let data = _.get(json, 'path', false);
if (data) {
state.groups[data.path] = new Set([data.members]);
}
}
}

View File

@ -9,13 +9,6 @@ export class InitialReducer {
state.chatInitialized = true; state.chatInitialized = true;
} }
data = _.get(json, 'group-initial', false);
if (data) {
for (let group in data) {
state.groups[group] = new Set(data[group]);
}
}
data = _.get(json, 'permission-initial', false); data = _.get(json, 'permission-initial', false);
if (data) { if (data) {
for (let perm in data) { for (let perm in data) {

View File

@ -1,5 +1,4 @@
import { InitialReducer } from '/reducers/initial'; import { InitialReducer } from '/reducers/initial';
import { GroupUpdateReducer } from '/reducers/group-update';
import { ContactUpdateReducer } from '/reducers/contact-update'; import { ContactUpdateReducer } from '/reducers/contact-update';
import { ChatUpdateReducer } from '/reducers/chat-update'; import { ChatUpdateReducer } from '/reducers/chat-update';
import { InviteUpdateReducer } from '/reducers/invite-update'; import { InviteUpdateReducer } from '/reducers/invite-update';
@ -13,7 +12,6 @@ class Store {
this.state = { this.state = {
inbox: {}, inbox: {},
chatSynced: {}, chatSynced: {},
groups: {},
contacts: {}, contacts: {},
permissions: {}, permissions: {},
invites: {}, invites: {},
@ -28,7 +26,6 @@ class Store {
}; };
this.initialReducer = new InitialReducer(); this.initialReducer = new InitialReducer();
this.groupUpdateReducer = new GroupUpdateReducer();
this.permissionUpdateReducer = new PermissionUpdateReducer(); this.permissionUpdateReducer = new PermissionUpdateReducer();
this.contactUpdateReducer = new ContactUpdateReducer(); this.contactUpdateReducer = new ContactUpdateReducer();
this.chatUpdateReducer = new ChatUpdateReducer(); this.chatUpdateReducer = new ChatUpdateReducer();
@ -47,7 +44,6 @@ class Store {
console.log(json); console.log(json);
this.initialReducer.reduce(json, this.state); this.initialReducer.reduce(json, this.state);
this.groupUpdateReducer.reduce(json, this.state);
this.permissionUpdateReducer.reduce(json, this.state); this.permissionUpdateReducer.reduce(json, this.state);
this.contactUpdateReducer.reduce(json, this.state); this.contactUpdateReducer.reduce(json, this.state);
this.chatUpdateReducer.reduce(json, this.state); this.chatUpdateReducer.reduce(json, this.state);

View File

@ -5,50 +5,46 @@ import urbitOb from 'urbit-ob';
export class Subscription { export class Subscription {
constructor() {
this.firstRoundSubscriptionComplete = false;
}
start() { start() {
if (api.authTokens) { if (api.authTokens) {
this.initializeChat(); this.firstRoundSubscription();
} else { } else {
console.error("~~~ ERROR: Must set api.authTokens before operation ~~~"); console.error("~~~ ERROR: Must set api.authTokens before operation ~~~");
} }
} }
initializeChat() { subscribe(path, app) {
api.bind('/primary', 'PUT', api.authTokens.ship, 'chat-view', api.bind(path, 'PUT', api.authTokens.ship, app,
this.handleEvent.bind(this), this.handleEvent.bind(this),
this.handleError.bind(this), this.handleError.bind(this),
this.handleQuitAndResubscribe.bind(this)); () => {
api.bind('/synced', 'PUT', api.authTokens.ship, 'chat-hook', this.subscribe(path, app);
this.handleEvent.bind(this), });
this.handleError.bind(this), }
this.handleQuitAndResubscribe.bind(this));
api.bind('/primary', 'PUT', api.authTokens.ship, 'invite-view', firstRoundSubscription() {
this.handleEvent.bind(this), this.subscribe('/primary', 'chat-view');
this.handleError.bind(this), }
this.handleQuitAndResubscribe.bind(this));
api.bind('/all', 'PUT', api.authTokens.ship, 'group-store', secondRoundSubscriptions() {
this.handleEvent.bind(this), this.subscribe('/synced', 'chat-hook');
this.handleError.bind(this), this.subscribe('/primary', 'invite-view');
this.handleQuitAndResubscribe.bind(this)); this.subscribe('/all', 'permission-store');
api.bind('/all', 'PUT', api.authTokens.ship, 'permission-store', this.subscribe('/primary', 'contact-view');
this.handleEvent.bind(this), this.subscribe('/app-name/chat', 'metadata-store');
this.handleError.bind(this), this.subscribe('/app-name/contacts', 'metadata-store');
this.handleQuitAndResubscribe.bind(this));
api.bind('/primary', 'PUT', api.authTokens.ship, 'contact-view',
this.handleEvent.bind(this),
this.handleError.bind(this),
this.handleQuitAndResubscribe.bind(this));
api.bind('/app-name/chat', 'PUT', api.authTokens.ship, 'metadata-store',
this.handleEvent.bind(this),
this.handleError.bind(this),
this.handleQuitAndResubscribe.bind(this));
api.bind('/app-name/contacts', 'PUT', api.authTokens.ship, 'metadata-store',
this.handleEvent.bind(this),
this.handleError.bind(this),
this.handleQuitAndResubscribe.bind(this));
} }
handleEvent(diff) { handleEvent(diff) {
if (!this.firstRoundSubscriptionComplete) {
this.firstRoundSubscriptionComplete = true;
this.secondRoundSubscriptions();
}
store.handleEvent(diff); store.handleEvent(diff);
} }
@ -56,14 +52,6 @@ export class Subscription {
console.error(err); console.error(err);
} }
handleQuitSilently(quit) {
// no-op
}
handleQuitAndResubscribe(quit) {
// TODO: resubscribe
}
fetchMessages(start, end, path) { fetchMessages(start, end, path) {
console.log(start, end, path); console.log(start, end, path);
fetch(`/~chat/paginate/${start}/${end}${path}`) fetch(`/~chat/paginate/${start}/${end}${path}`)