Comments (2)
We're getting to the point where we can finally get rid of all the code on the server that is constantly sending down userInfos
. There is a lot of historical cruft to deal with here, so I wanted to take the time to outline the steps we'll need to go through in order to do this.
Step 1: making sure server updates clients when their userStore
should change
userStore
should changeThis step is almost complete, but there was one oversight I missed during review.
In commitMembershipChangeset
, we call updateUndirectedRelationships
to update the DB with our new relationships. However, updating the DB is not enough - we also need to issue updateTypes.UPDATE_USER
to make sure that clients get the update. Otherwise, they will only see the update if they do a full state sync.
I think we should extract these lines into a new function: https://github.com/Ashoat/squadcal/blob/2739065ff9445795a6e1df0f4a5e90db3c5fcdd0/server/src/updaters/relationship-updaters.js#L171-L186
We can then merge the updateTypes.UPDATE_USER
with the other updateDatas
in commitMembershipChangeset
. Let's make sure that the updateTypes.UPDATE_USER
come before the other updateDatas
in the array. This doesn't currently affect anything, since right now we guarantee that a batch of updates created together will always be delivered together. But just in case we break this assumption in the future, we should make sure the updateTypes.UPDATE_USER
updates come first.
Step 2: handle users who have left a thread
This is a continuation of step 1, but it's an edge case I realized we hadn't considered previously. This is probably the hardest step on this list.
Right now, when the server sends down a message or a calendar entry, it makes sure to send down the UserInfo
of the author as well. This guarantees that if an author has left the thread before a new user has been added to it, the new user still gets the UserInfo
object.
We don't currently consider this case in our userStore
syncing logic. I think we will have to rethink some of the logic in thread-permission-updaters.js
, unfortunately.
The solution I have in mind is to keep a membership
row for a user, even after they leave a thread. We can use role = -1
to signify a former member, and we can edit the permissions
column to support NULL
values.
In every existing SQL query that touches memberships
, we should make sure to only return rows where role >= 0
. The only exception will be in thread-permission-updaters.js
, where we will make sure to only look at role = -1
rows when determining relationship
rows.
We'll need to update deleteMemberships
to do an UPDATE
instead of a DELETE FROM
.
We will also need to update the create-relationships.js
migration to look at any users who have sent a message or created a calendar entry for a given thread.
Step 3: update state sync
We have two kinds of state sync: incremental and full. Full state sync will still need userInfos
, but can get it via a single fetchKnownUserInfos
fetch instead of combining userInfos
from multiple sources.
Incremental state sync will be more complicated. It might seem like we can get rid of the userInfos
key. But there is an important quirk to how updateTypes.UPDATE_USER
works:
In short, the UpdateInfo
for updateTypes.UPDATE_USER
does not include a UserInfo
object. Instead, we rely on the UserInfo
object being included in the userInfos
that are returned from createUpdates
and fetchUpdateInfosWithQuery
.
That means that in order to avoid breaking old clients, we need to keep sending them a userInfos
key in the incremental state sync.
For new clients, we could move the UserInfo
objects to the actual updateTypes.UPDATE_USER
updates, and then we could get rid of the userInfos
key. But I think this probably isn't worth our time right now.
The easiest thing would be to update the incremental state sync so it only returns the userInfos
that we get from the updatesResult
here:
Step 4: update createUpdates
and fetchUpdateInfosWithQuery
These two functions are the only places where the server constructs UpdateInfo
objects to return to the client. createUpdates
gets called when an update is first created, and makes sure to propagate any updates to clients with an active socket. For any non-active clients, a row is added to the MySQL table updates
. The next time those clients connect, fetchUpdateInfosWithQuery
looks at the MySQL table, creates UpdateInfos
from the rows, and then returns them to the client.
Both of these functions go through updateInfosFromRawUpdateInfos
, which handles constructing userInfos
for FetchUpdatesResult
. Right now we include any userInfos
that are relevant to an update. We should update this code so we only include userInfos
from updateTypes.UPDATE_USER
.
Step 5: update MessagesServerSocketMessage
Just like createUpdates
, createMessages
is set up to immediately deliver messages to any clients with an active socket. Right now it includes the UserInfos
of any message authors, but we don't need to do this going forward.
Actually, it looks like the client was never looking at the userInfos
field of MessagesResultWithUserInfos
anyways! I think we can safely remove this field entirely. No need to return an empty object, since it looks like no client has ever looked there.
Step 6: clean up actions/responders that currently deliver userInfos
We have several client/server interactions that currently deliver userInfos
to the client. We don't need these anymore. The full list is covered by this conditional at the top of reduceUserInfos
:
searchUsersActionTypes
is a special case. Current clients rely on this returning UserInfo
s, and it isn't handled by any updateTypes.UPDATE_USER
. So we need to let the server continue returning UserInfo
s here. However, we can update new clients to no longer merge the UserInfo
s into the userStore
, especially since this will confuse the state check mechanism.
joinThreadActionTypes
is also a special case, because the server currently extracts the userInfos
from the updatesResult
and puts them in action.payload.userInfos
. We should update the server so that it only includes the UserInfos
from updatesResult
here, but it will be easiest to leave the client alone.
For the other four, I don't think we need to return userInfos
from the server anymore. Since old clients will continue expecting an object in action.payload.userInfos
, I think it will be easiest to just return an empty object here.
For new clients, we should update reduceUserInfos
so it no longer looks at these actions at all.
Step 7: clean up entry logic that currently delivers userInfos
This is kind of a continuation of step 6. reducerUserInfos
currently handles calendar entry updates in a separate section:
Similar to step 6, I don't think the server needs to return userInfos
here anymore. I think once step 4 is complete, we will automatically be returning an empty object here anyways.
I think the only thing we need to do for these is to update the client code. New clients shouldn't need to look at these actions at all.
Step 8: createAccountDeletionUpdates
in deleteAccount
This part should be pretty easy. Right now when a user deletes an account, we tell every single client. We should update this so we only tell clients whose users have a know_of
row with the deleted account.
Step 9: clean up server fetchers
Finally!! We are almost done. The last step is to clean up all of the remaining server code. I think most of this will be in server/src/fetchers
. Functions like fetchThreadInfos
currently return a list of UserInfo
s, but they shouldn't need to anymore.
Any SQL query where you see u.username
is probably an example of something that needs to be cleaned up. I think there are three files we need to fix up:
server/src/fetchers/entry-fetchers.js
server/src/fetchers/message-fetchers.js
server/src/fetchers/thread-fetchers.js
from comm.
Note - I addressed step 1 in 28bb013
from comm.
Related Issues (20)
- Personal threads HOT 5
- Make it possible to see history of threads you have left
- Prevent blocked users from messaging each other HOT 6
- Redesign friend/block list
- Replace ComposeThread HOT 8
- Private thread
- Security Issue: Request for contact HOT 1
- Improve search results view
- Deal with iOS 14's limited photo library permissions HOT 1
- Redesign calendar HOT 1
- Support native share dialogs
- Replies for non-text messages
- Update robotext message when thread type is changed HOT 2
- Handling multiline select on web
- Sidebar inline replies number HOT 2
- Header oscillates when opening emojis on keyboard HOT 1
- Thing
- pod install fails with use_expo_modules!
- xcode ios: failed to run custom build command for `native_rust_library v0.1.0` HOT 12
- please stop paging me with @ mentions HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from comm.