cinny/src/client/action/room.js

309 lines
8.1 KiB
JavaScript
Raw Normal View History

2021-07-28 15:15:52 +02:00
import initMatrix from '../initMatrix';
import appDispatcher from '../dispatcher';
import cons from '../state/cons';
import { getIdServer } from '../../util/matrixUtil';
2021-07-28 15:15:52 +02:00
/**
* https://github.com/matrix-org/matrix-react-sdk/blob/1e6c6e9d800890c732d60429449bc280de01a647/src/Rooms.js#L73
* @param {string} roomId Id of room to add
* @param {string} userId User id to which dm
* @returns {Promise} A promise
*/
function addRoomToMDirect(roomId, userId) {
const mx = initMatrix.matrixClient;
const mDirectsEvent = mx.getAccountData('m.direct');
let userIdToRoomIds = {};
if (typeof mDirectsEvent !== 'undefined') userIdToRoomIds = mDirectsEvent.getContent();
// remove it from the lists of any others users
// (it can only be a DM room for one person)
Object.keys(userIdToRoomIds).forEach((thisUserId) => {
const roomIds = userIdToRoomIds[thisUserId];
if (thisUserId !== userId) {
const indexOfRoomId = roomIds.indexOf(roomId);
if (indexOfRoomId > -1) {
roomIds.splice(indexOfRoomId, 1);
}
}
});
// now add it, if it's not already there
if (userId) {
const roomIds = userIdToRoomIds[userId] || [];
if (roomIds.indexOf(roomId) === -1) {
roomIds.push(roomId);
}
userIdToRoomIds[userId] = roomIds;
}
return mx.setAccountData('m.direct', userIdToRoomIds);
}
/**
* Given a room, estimate which of its members is likely to
* be the target if the room were a DM room and return that user.
* https://github.com/matrix-org/matrix-react-sdk/blob/1e6c6e9d800890c732d60429449bc280de01a647/src/Rooms.js#L117
*
* @param {Object} room Target room
* @param {string} myUserId User ID of the current user
* @returns {string} User ID of the user that the room is probably a DM with
*/
function guessDMRoomTargetId(room, myUserId) {
let oldestMemberTs;
let oldestMember;
// Pick the joined user who's been here longest (and isn't us),
room.getJoinedMembers().forEach((member) => {
if (member.userId === myUserId) return;
if (typeof oldestMemberTs === 'undefined' || (member.events.member && member.events.member.getTs() < oldestMemberTs)) {
oldestMember = member;
oldestMemberTs = member.events.member.getTs();
}
});
if (oldestMember) return oldestMember.userId;
// if there are no joined members other than us, use the oldest member
room.currentState.getMembers().forEach((member) => {
if (member.userId === myUserId) return;
if (typeof oldestMemberTs === 'undefined' || (member.events.member && member.events.member.getTs() < oldestMemberTs)) {
oldestMember = member;
oldestMemberTs = member.events.member.getTs();
}
});
if (typeof oldestMember === 'undefined') return myUserId;
return oldestMember.userId;
}
/**
*
* @param {string} roomId
* @param {boolean} isDM
* @param {string[]} via
2021-07-28 15:15:52 +02:00
*/
async function join(roomIdOrAlias, isDM, via) {
2021-07-28 15:15:52 +02:00
const mx = initMatrix.matrixClient;
const roomIdParts = roomIdOrAlias.split(':');
const viaServers = via || [roomIdParts[1]];
try {
const resultRoom = await mx.joinRoom(roomIdOrAlias, { viaServers });
if (isDM) {
const targetUserId = guessDMRoomTargetId(mx.getRoom(resultRoom.roomId), mx.getUserId());
await addRoomToMDirect(resultRoom.roomId, targetUserId);
}
appDispatcher.dispatch({
type: cons.actions.room.JOIN,
roomId: resultRoom.roomId,
isDM,
});
return resultRoom.roomId;
} catch (e) {
throw new Error(e);
}
2021-07-28 15:15:52 +02:00
}
/**
*
* @param {string} roomId
* @param {boolean} isDM
*/
2022-05-04 10:52:16 +02:00
async function leave(roomId) {
2021-07-28 15:15:52 +02:00
const mx = initMatrix.matrixClient;
const isDM = initMatrix.roomList.directs.has(roomId);
2022-05-04 10:52:16 +02:00
try {
await mx.leave(roomId);
appDispatcher.dispatch({
type: cons.actions.room.LEAVE,
roomId,
isDM,
});
} catch {
console.error('Unable to leave room.');
}
2021-07-28 15:15:52 +02:00
}
async function create(options, isDM = false) {
2021-07-28 15:15:52 +02:00
const mx = initMatrix.matrixClient;
try {
const result = await mx.createRoom(options);
if (isDM && typeof options.invite?.[0] === 'string') {
await addRoomToMDirect(result.room_id, options.invite[0]);
2021-07-28 15:15:52 +02:00
}
appDispatcher.dispatch({
type: cons.actions.room.CREATE,
roomId: result.room_id,
isDM,
2021-07-28 15:15:52 +02:00
});
return result;
} catch (e) {
const errcodes = ['M_UNKNOWN', 'M_BAD_JSON', 'M_ROOM_IN_USE', 'M_INVALID_ROOM_STATE', 'M_UNSUPPORTED_ROOM_VERSION'];
if (errcodes.includes(e.errcode)) {
2021-07-28 15:15:52 +02:00
throw new Error(e);
}
throw new Error('Something went wrong!');
}
}
async function createDM(userId, isEncrypted = true) {
const options = {
is_direct: true,
invite: [userId],
visibility: 'private',
preset: 'trusted_private_chat',
initial_state: [],
};
if (isEncrypted) {
options.initial_state.push({
type: 'm.room.encryption',
state_key: '',
content: {
algorithm: 'm.megolm.v1.aes-sha2',
},
});
}
const result = await create(options, true);
return result;
}
async function createRoom(opts) {
// joinRule: 'public' | 'invite' | 'restricted'
const { name, topic, joinRule } = opts;
const alias = opts.alias ?? undefined;
const parentId = opts.parentId ?? undefined;
const isSpace = opts.isSpace ?? false;
const isEncrypted = opts.isEncrypted ?? false;
const powerLevel = opts.powerLevel ?? undefined;
const blockFederation = opts.blockFederation ?? false;
const mx = initMatrix.matrixClient;
const visibility = joinRule === 'public' ? 'public' : 'private';
const options = {
creation_content: undefined,
name,
topic,
visibility,
room_alias_name: alias,
initial_state: [],
power_level_content_override: undefined,
};
if (isSpace) {
options.creation_content = { type: 'm.space' };
}
if (blockFederation) {
options.creation_content = { 'm.federate': false };
}
if (isEncrypted) {
options.initial_state.push({
type: 'm.room.encryption',
state_key: '',
content: {
algorithm: 'm.megolm.v1.aes-sha2',
},
});
}
if (powerLevel) {
options.power_level_content_override = {
users: {
[mx.getUserId()]: powerLevel,
},
};
}
if (parentId) {
options.initial_state.push({
type: 'm.space.parent',
state_key: parentId,
content: {
canonical: true,
via: [getIdServer(mx.getUserId())],
},
});
}
if (parentId && joinRule === 'restricted') {
try {
const caps = await mx.getCapabilities();
options.room_version = caps
?.['m.room_versions']
?.['org.matrix.msc3244.room_capabilities']
?.restricted
?.preferred
|| undefined;
} catch {
console.error('Can\'t find room version for restricted.');
}
options.initial_state.push({
type: 'm.room.join_rules',
content: {
join_rule: 'restricted',
allow: [{
type: 'm.room_membership',
room_id: parentId,
}],
},
});
}
const result = await create(options);
if (parentId) {
await mx.sendStateEvent(parentId, 'm.space.child', {
auto_join: false,
suggested: false,
via: [getIdServer(mx.getUserId())],
}, result.room_id);
}
return result;
}
2021-07-28 15:15:52 +02:00
async function invite(roomId, userId) {
const mx = initMatrix.matrixClient;
const result = await mx.invite(roomId, userId);
return result;
}
async function kick(roomId, userId, reason) {
const mx = initMatrix.matrixClient;
const result = await mx.kick(roomId, userId, reason);
return result;
2021-07-28 15:15:52 +02:00
}
async function ban(roomId, userId, reason) {
const mx = initMatrix.matrixClient;
const result = await mx.ban(roomId, userId, reason);
return result;
}
async function unban(roomId, userId) {
const mx = initMatrix.matrixClient;
const result = await mx.unban(roomId, userId);
return result;
}
async function setPowerLevel(roomId, userId, powerLevel) {
const mx = initMatrix.matrixClient;
const room = mx.getRoom(roomId);
const powerlevelEvent = room.currentState.getStateEvents('m.room.power_levels')[0];
const result = await mx.setPowerLevel(roomId, userId, powerLevel, powerlevelEvent);
return result;
}
2021-07-28 15:15:52 +02:00
export {
2021-08-12 06:12:12 +02:00
join, leave,
createDM, createRoom,
invite, kick, ban, unban,
setPowerLevel,
2021-07-28 15:15:52 +02:00
};