-
Notifications
You must be signed in to change notification settings - Fork 124
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
Peeking unknown rooms #1037
base: master
Are you sure you want to change the base?
Peeking unknown rooms #1037
Changes from all commits
d468abd
8b56a0d
9fa2f71
c76e45d
5bc5ca0
4439fb3
220fe38
2fb9cb6
654cdf0
07cce38
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ limitations under the License. | |
import {LeftPanelViewModel} from "./leftpanel/LeftPanelViewModel.js"; | ||
import {RoomViewModel} from "./room/RoomViewModel.js"; | ||
import {UnknownRoomViewModel} from "./room/UnknownRoomViewModel.js"; | ||
import {WorldReadableRoomViewModel} from "./room/WorldReadableRoomViewModel.js"; | ||
import {InviteViewModel} from "./room/InviteViewModel.js"; | ||
import {RoomBeingCreatedViewModel} from "./room/RoomBeingCreatedViewModel.js"; | ||
import {LightboxViewModel} from "./room/LightboxViewModel.js"; | ||
|
@@ -231,13 +232,23 @@ export class SessionViewModel extends ViewModel { | |
return null; | ||
} | ||
|
||
_createUnknownRoomViewModel(roomIdOrAlias) { | ||
_createUnknownRoomViewModel(roomIdOrAlias, isWorldReadablePromise) { | ||
return new UnknownRoomViewModel(this.childOptions({ | ||
roomIdOrAlias, | ||
session: this._client.session, | ||
isWorldReadablePromise: isWorldReadablePromise | ||
})); | ||
} | ||
|
||
async _createWorldReadableRoomViewModel(roomIdOrAlias) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this method used anywhere? |
||
const roomVM = new WorldReadableRoomViewModel(this.childOptions({ | ||
room: await this._client.session.loadWorldReadableRoom(roomIdOrAlias), | ||
session: this._client.session, | ||
})); | ||
roomVM.load(); | ||
return roomVM; | ||
} | ||
|
||
async _createArchivedRoomViewModel(roomId) { | ||
const room = await this._client.session.loadArchivedRoom(roomId); | ||
if (room) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,7 @@ export class RoomViewModel extends ErrorReportViewModel { | |
this._composerVM = null; | ||
if (room.isArchived) { | ||
this._composerVM = this.track(new ArchivedViewModel(this.childOptions({archivedRoom: room}))); | ||
} else { | ||
} else if (!room.isWorldReadable) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see this property ( |
||
this._recreateComposerOnPowerLevelChange(); | ||
} | ||
this._clearUnreadTimout = null; | ||
|
@@ -218,7 +218,7 @@ export class RoomViewModel extends ErrorReportViewModel { | |
} | ||
} | ||
} | ||
|
||
_sendMessage(message, replyingTo) { | ||
return this.logAndCatch("RoomViewModel.sendMessage", async log => { | ||
let success = false; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import {RoomViewModel} from "./RoomViewModel"; | ||
|
||
export class WorldReadableRoomViewModel extends RoomViewModel { | ||
constructor(options) { | ||
options.room.isWorldReadable = true; | ||
super(options); | ||
this._room = options.room; | ||
this._session = options.session; | ||
this._error = null; | ||
this._busy = false; | ||
} | ||
|
||
get kind() { | ||
return "preview"; | ||
} | ||
|
||
get busy() { | ||
return this._busy; | ||
} | ||
|
||
async join() { | ||
this._busy = true; | ||
this.emitChange("busy"); | ||
try { | ||
const roomId = await this._session.joinRoom(this._room.id); | ||
// navigate to roomId if we were at the alias | ||
// so we're subscribed to the right room status | ||
// and we'll switch to the room view model once | ||
// the join is synced | ||
this.navigation.push("room", roomId); | ||
// keep busy on true while waiting for the join to sync | ||
} catch (err) { | ||
this._error = err; | ||
this._busy = false; | ||
this.emitChange("error"); | ||
} | ||
} | ||
|
||
dispose() { | ||
super.dispose(); | ||
|
||
// if joining the room, _busy would be true and in that case don't delete records | ||
if (!this._busy) { | ||
void this._session.deleteWorldReadableRoomData(this._room.id); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -49,6 +49,8 @@ import {SecretStorage} from "./ssss/SecretStorage"; | |||||
import {ObservableValue, RetainedObservableValue} from "../observable/value"; | ||||||
import {CallHandler} from "./calls/CallHandler"; | ||||||
import {RoomStateHandlerSet} from "./room/state/RoomStateHandlerSet"; | ||||||
import {EventKey} from "./room/timeline/EventKey"; | ||||||
import {createEventEntry} from "./room/timeline/persistence/common"; | ||||||
|
||||||
const PICKLE_KEY = "DEFAULT_KEY"; | ||||||
const PUSHER_KEY = "pusher"; | ||||||
|
@@ -655,6 +657,22 @@ export class Session { | |||||
return room; | ||||||
} | ||||||
|
||||||
/** @internal */ | ||||||
_createWorldReadableRoom(roomId) { | ||||||
return new Room({ | ||||||
roomId, | ||||||
getSyncToken: this._getSyncToken, | ||||||
storage: this._storage, | ||||||
emitCollectionChange: this._roomUpdateCallback, | ||||||
hsApi: this._hsApi, | ||||||
mediaRepository: this._mediaRepository, | ||||||
pendingEvents: [], | ||||||
user: this._user, | ||||||
platform: this._platform, | ||||||
roomStateHandler: this._roomStateHandler | ||||||
}); | ||||||
} | ||||||
|
||||||
get invites() { | ||||||
return this._invites; | ||||||
} | ||||||
|
@@ -1031,12 +1049,135 @@ export class Session { | |||||
}); | ||||||
} | ||||||
|
||||||
loadWorldReadableRoom(roomId, log = null) { | ||||||
return this._platform.logger.wrapOrRun(log, "loadWorldReadableRoom", async log => { | ||||||
log.set("id", roomId); | ||||||
|
||||||
const room = this._createWorldReadableRoom(roomId); | ||||||
let response = await this._fetchWorldReadableRoomEvents(roomId, 100, 'b', null, log); | ||||||
// Note: response.end to be used in the next call for sync functionality | ||||||
|
||||||
let summary = await this._prepareWorldReadableRoomSummary(roomId, log); | ||||||
const txn = await this._storage.readTxn([ | ||||||
this._storage.storeNames.timelineFragments, | ||||||
this._storage.storeNames.timelineEvents, | ||||||
this._storage.storeNames.roomMembers, | ||||||
]); | ||||||
await room.load(summary, txn, log); | ||||||
|
||||||
return room; | ||||||
}); | ||||||
} | ||||||
|
||||||
async _prepareWorldReadableRoomSummary(roomId, log = null) { | ||||||
return this._platform.logger.wrapOrRun(log, "prepareWorldReadableRoomSummary", async log => { | ||||||
log.set("id", roomId); | ||||||
|
||||||
let summary = {}; | ||||||
const resp = await this._hsApi.currentState(roomId).response(); | ||||||
for ( let i=0; i<resp.length; i++ ) { | ||||||
if ( resp[i].type === 'm.room.name') { | ||||||
summary["name"] = resp[i].content.name; | ||||||
} else if ( resp[i].type === 'm.room.canonical_alias' ) { | ||||||
summary["canonicalAlias"] = resp[i].content.alias; | ||||||
} else if ( resp[i].type === 'm.room.avatar' ) { | ||||||
summary["avatarUrl"] = resp[i].content.url; | ||||||
} | ||||||
} | ||||||
Comment on lines
+1077
to
+1086
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We usually use |
||||||
|
||||||
return summary; | ||||||
}); | ||||||
} | ||||||
|
||||||
async _fetchWorldReadableRoomEvents(roomId, limit = 30, dir = 'b', end = null, log = null) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a typescript const enum for |
||||||
return this._platform.logger.wrapOrRun(log, "fetchWorldReadableRoomEvents", async log => { | ||||||
log.set("id", roomId); | ||||||
let options = { | ||||||
limit: limit, | ||||||
dir: 'b', | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
filter: { | ||||||
lazy_load_members: true, | ||||||
include_redundant_members: true, | ||||||
} | ||||||
} | ||||||
if (end !== null) { | ||||||
options['from'] = end; | ||||||
} | ||||||
|
||||||
const response = await this._hsApi.messages(roomId, options, {log}).response(); | ||||||
log.set("/messages endpoint response", response); | ||||||
|
||||||
await this.deleteWorldReadableRoomData(roomId, log); | ||||||
|
||||||
const txn = await this._storage.readWriteTxn([ | ||||||
this._storage.storeNames.timelineFragments, | ||||||
this._storage.storeNames.timelineEvents, | ||||||
]); | ||||||
|
||||||
// insert fragment and event records for this room | ||||||
const fragment = { | ||||||
roomId: roomId, | ||||||
id: 0, | ||||||
previousId: null, | ||||||
nextId: null, | ||||||
previousToken: response.start, | ||||||
nextToken: null, | ||||||
}; | ||||||
txn.timelineFragments.add(fragment); | ||||||
|
||||||
let eventKey = EventKey.defaultLiveKey; | ||||||
for (let i = 0; i < response.chunk.length; i++) { | ||||||
if (i) { | ||||||
eventKey = eventKey.previousKey(); | ||||||
} | ||||||
let txn = await this._storage.readWriteTxn([this._storage.storeNames.timelineEvents]); | ||||||
let eventEntry = createEventEntry(eventKey, roomId, response.chunk[i]); | ||||||
await txn.timelineEvents.tryInsert(eventEntry, log); | ||||||
} | ||||||
|
||||||
return response; | ||||||
}); | ||||||
} | ||||||
|
||||||
async deleteWorldReadableRoomData(roomId, log = null) { | ||||||
return this._platform.logger.wrapOrRun(log, "deleteWorldReadableRoomData", async log => { | ||||||
log.set("id", roomId); | ||||||
|
||||||
const txn = await this._storage.readWriteTxn([ | ||||||
this._storage.storeNames.timelineFragments, | ||||||
this._storage.storeNames.timelineEvents, | ||||||
]); | ||||||
|
||||||
// clear old records for this room | ||||||
txn.timelineFragments.removeAllForRoom(roomId); | ||||||
txn.timelineEvents.removeAllForRoom(roomId); | ||||||
}); | ||||||
} | ||||||
|
||||||
joinRoom(roomIdOrAlias, log = null) { | ||||||
return this._platform.logger.wrapOrRun(log, "joinRoom", async log => { | ||||||
const body = await this._hsApi.joinIdOrAlias(roomIdOrAlias, {log}).response(); | ||||||
return body.room_id; | ||||||
}); | ||||||
} | ||||||
|
||||||
async isWorldReadableRoom(roomIdOrAlias, log = null) { | ||||||
return this._platform.logger.wrapOrRun(log, "isWorldReadableRoom", async log => { | ||||||
try { | ||||||
let roomId; | ||||||
if (!roomIdOrAlias.startsWith("!")) { | ||||||
let response = await this._hsApi.resolveRoomAlias(roomIdOrAlias).response(); | ||||||
roomId = response.room_id; | ||||||
} else { | ||||||
roomId = roomIdOrAlias; | ||||||
} | ||||||
const body = await this._hsApi.state(roomId, 'm.room.history_visibility', '', {log}).response(); | ||||||
return body.history_visibility === 'world_readable'; | ||||||
} catch { | ||||||
return false; | ||||||
} | ||||||
}); | ||||||
} | ||||||
} | ||||||
|
||||||
import {FeatureSet} from "../features"; | ||||||
|
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.