-
Notifications
You must be signed in to change notification settings - Fork 88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor create community #2305
Conversation
156fe39
to
5d86954
Compare
a8db4ee
to
5bd37ad
Compare
} else { | ||
this.logger('Nothing to migrate') | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are moving the Community model to the backend, new communities created after this code is released will have the Community model in the backend, however existing communities that upgrade Quiet need to have their community data migrated - that's what this function is for.
await this.localDbService.put(LocalDBKeys.PSK, pskBase64) | ||
this.logger('Generated Libp2p PSK') | ||
this.serverIoProvider.io.emit(SocketActionTypes.LIBP2P_PSK_STORED, { psk: pskBase64 }) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We store the psk in the Community object, so there is no more need for the PSK key in LevelDB. We also return the entire Community object from createCommunity so there is no more need for the LIBP2P_PSK_STORED event.
} catch (e) { | ||
this.logger.error('Failed to register owner certificate') | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We register the owner certificate in createCommunity since that's how it was done before in sagas. We previously called REGISTER_OWNER_CERTIFICATE and then when that completed, we called CREATED_COMMUNITY. Now we do it all together. However, we may want to decouple the owner cert from the community in future work.
public async launchCommunity(payload: InitCommunityPayload) { | ||
this.logger('Launching community: peers:', payload.peers) | ||
this.communityState = ServiceState.LAUNCHING | ||
public async joinCommunity(payload: InitCommunityPayload): Promise<Community | undefined> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
joinCommunity is a new function so that we can focus on validation and creating a Community object, while launchCommunity is still used but it's only for launching an already-validated community.
emitError(this.serverIoProvider.io, payload) | ||
}) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed anymore since we call to the registration service directly and await on its return
...community, | ||
ownerOrbitDbIdentity: meta.ownerOrbitDbIdentity, | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update Community object on backend when setting CommunityMetadata. This is the first time that ownerOrbitDbIdentity is available. In the future, we can do this all when creating the community and remove this SET_COMMUNITY_METADATA event.
async (args: RegisterOwnerCertificatePayload) => { | ||
await this.registrationService.registerOwnerCertificate(args) | ||
} | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No longer required - we do this in createCommunity
@@ -609,8 +724,8 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI | |||
this.storageService.on(StorageEvents.MESSAGE_MEDIA_UPDATED, (payload: FileMetadata) => { | |||
this.serverIoProvider.io.emit(SocketActionTypes.MESSAGE_MEDIA_UPDATED, payload) | |||
}) | |||
this.storageService.on(StorageEvents.UPDATE_PEERS_LIST, (payload: StorePeerListPayload) => { | |||
this.serverIoProvider.io.emit(SocketActionTypes.PEER_LIST, payload) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of sending an event for a single piece of data (e.g. peerList), we send a general event (COMMUNITY_UPDATED) anytime the backend updates the Community model so that the frontend can replicate the state.
await this.localDbService.setCommunity(updatedCommunity) | ||
|
||
this.serverIoProvider.io.emit(SocketActionTypes.COMMUNITY_UPDATED, updatedCommunity) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When another peer receives the CommunityMetadata from OrbitDB, they update their Community object in LevelDB and then notify the frontend via COMMUNITY_UPDATED.
COMMUNITIES = 'communities', | ||
// ID of current community | ||
CURRENT_COMMUNITY_ID = 'currentCommunityId', | ||
// Record of peer details | ||
PEERS = 'peers', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Backend LevelDB state mirrors the way things have been organized in Redux
message: ErrorMessages.REGISTRATION_FAILED, | ||
community: payload.communityId, | ||
}) | ||
throw new Error('Failed to register owner certificate') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing events since we can call this directly and await it
} | ||
|
||
yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.LOAD_MIGRATION_DATA, data)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Saga for sending frontend data to the backend in order to migrate existing communities when upgrading Quiet.
packages/state-manager/src/sagas/communities/communities.slice.ts
Outdated
Show resolved
Hide resolved
// community creation from CSR/certificate creation and create the community | ||
// first and then add the owner's CSR and issue their certificate. | ||
yield* put(identityActions.saveUserCsr()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I renamed savedOwnerCertificate.saga.ts to createCommunity.saga.ts and modified it a bit. We generate the owner's certificate when creating the community now and just call updateCommunityData with the returned Community object.
if (psk) { | ||
console.log('create network saga: saving PSK') | ||
yield* put(communitiesActions.savePSK(psk)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for this anymore, otherwise just reorganizing things a bit.
ownerCertificate: action.payload.ownerCertificate, | ||
}) | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now when CommunityMetadata is received from OrbitDB, we update the Community on the backend and then emit a COMMUNITY_UPDATED event. This isn't needed anymore.
} | ||
|
||
yield* put(communitiesActions.updateCommunityData(payload)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now when CommunityMetadata is received from OrbitDB, we update the Community on the backend and then emit a COMMUNITY_UPDATED event. This isn't needed anymore.
|
||
if (meta) { | ||
yield* put(communitiesActions.saveCommunityMetadata(meta)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also replaced by a COMMUNITY_UPDATED event. Going forward, we can remove this saga entirely.
} | ||
|
||
yield* apply(socket, socket.emit, applyEmitParams(SocketActionTypes.CREATE_COMMUNITY, payload)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was renamed to createCommunity.saga.ts
// all the backend services up and running and then save the | ||
// CSR, register the owner's certificate and set community | ||
// metadata. | ||
emit(identityActions.saveUserCsr()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we are using an acknowledgement for the CREATE_COMMUNITY event, this was moved into createCommunitySaga
@@ -11,8 +11,6 @@ export interface Community { | |||
rootCa?: string | |||
peerList?: string[] | |||
onionAddress?: string | |||
privateKey?: string | |||
port?: number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently unused
peerId: PeerId | ||
hiddenService: HiddenService | ||
certs?: Certificates |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also apparently unused
454011d
to
bc0510b
Compare
|
||
// Only require migration data for existing communities. We can tell because | ||
// they are using the deprecated COMMUNITY key in LevelDB. This is related | ||
// to a specific migration. Perhaps we want a more general purpose migration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's definitely a good idea especially that leveldb will be storing more data from now on. We can get inspiration from Django migrations files or any other migration mechanism.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea I was thinking about something like that
await this.tor.destroyHiddenService(hiddenService.onionAddress.split('.')[0]) | ||
|
||
// TODO: Do we want to create the PeerId here? It doesn't necessarily have |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose it was added here because it's needed to create full peer's p2p address in order for peer to join the network. So it's kind of related. But we don't have to do that here.
const communityName = getCertFieldValue(rootCaCert, CertFieldsTypes.commonName) | ||
|
||
if (!communityName) { | ||
this.logger.error(`Could not retrieve ${CertFieldsTypes.commonName} from CommunityMetadata.rootCa`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If rootCa doesn't have commonName there may be something wrong with rootCa. Are we sure that we still want to update community metadata in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code runs after community metadata has been updated. I think I mostly copied it from sagas. I think we can definitely improve things. My feeling is we should probably validate the rootCA somewhere when it's first created and then trust it from then on.
async (payload: CommunityMetadata, callback: (response?: CommunityMetadata) => void) => { | ||
const meta = await this.storageService?.updateCommunityMetadata(payload) | ||
async (payload: CommunityMetadata, callback: (response: CommunityMetadata | undefined) => void) => { | ||
const meta = await this.storageService.updateCommunityMetadata(payload) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that you added throwing exception in updateCommunityMetadata. Maybe we should catch it here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is the exception? I think I'm missing it.
packages/state-manager/src/sagas/communities/communities.slice.ts
Outdated
Show resolved
Hide resolved
|
||
jest.setTimeout(20_000) | ||
|
||
describe('General channel', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is it deleted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is fully tested in community.create and community.join tests
bc0510b
to
2227744
Compare
… into refactor-create-community
This PR migrates the Community model to the backend so that the backend is now the source of truth for Community data. In order to accomplish this, for existing communities (existing Quiet install), we move (migrate) the data from the frontend to the backend and then make sure all operations that previously affected the frontend Community state are done on the backend. For new communities (new Quiet install), some of the logic for creating/joining has been moved to the backend and the event-flow is simplified. Whenever the Community model is updated on the backend, the backend now emits a COMMUNITY_UPDATED event so that the frontend can synchronize its Community state.
Solution for: #2329
Pull Request Checklist
(Optional) Mobile checklist
Please ensure you completed the following checks if you did any changes to the mobile package: