mx-puppet-bridge
Advanced tools
Comparing version 0.0.8 to 0.0.9
@@ -175,3 +175,4 @@ "use strict"; | ||
default: | ||
yield this.sendMessage(roomId, `Available commands: help, list, link, unlink, setmatrixtoken, listusers, listchannels`); | ||
yield this.sendMessage(roomId, "Available commands: help, list, link, " + | ||
"unlink, setmatrixtoken, listusers, listchannels"); | ||
} | ||
@@ -178,0 +179,0 @@ }); |
@@ -70,106 +70,114 @@ "use strict"; | ||
log.info(`Fetching mxid for roomId ${data.roomId} and puppetId ${data.puppetId}`); | ||
if (!client) { | ||
client = this.bridge.botIntent.underlyingClient; | ||
} | ||
let chan = yield this.chanStore.getByRemote(data.puppetId, data.roomId); | ||
log.silly(chan); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
topic: false, | ||
}; | ||
let mxid = ""; | ||
let doUpdate = false; | ||
let created = false; | ||
if (!chan) { | ||
if (!doCreate) { | ||
this.mxidLock.release(lockKey); | ||
return { | ||
mxid: "", | ||
created: false, | ||
try { | ||
if (!client) { | ||
client = this.bridge.botIntent.underlyingClient; | ||
} | ||
let chan = yield this.chanStore.getByRemote(data.puppetId, data.roomId); | ||
log.silly(chan); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
topic: false, | ||
}; | ||
let mxid = ""; | ||
let doUpdate = false; | ||
let created = false; | ||
if (!chan) { | ||
if (!doCreate) { | ||
this.mxidLock.release(lockKey); | ||
return { | ||
mxid: "", | ||
created: false, | ||
}; | ||
} | ||
log.info("Channel doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createChan) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = yield this.bridge.hooks.createChan(data); | ||
if (newData && newData.puppetId === data.puppetId && newData.roomId === data.roomId) { | ||
data = newData; | ||
} | ||
else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
} | ||
} | ||
log.verbose("Creation data:", data); | ||
log.verbose("Initial invites:", invites); | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
update.topic = data.topic ? true : false; | ||
// ooookay, we need to create this channel | ||
const createParams = { | ||
visibility: "private", | ||
preset: "private_chat", | ||
power_level_content_override: { | ||
notifications: { | ||
room: 0, | ||
}, | ||
}, | ||
is_direct: data.isDirect, | ||
invite: invites, | ||
}; | ||
if (!data.isDirect) { | ||
// we also want to set an alias for later reference | ||
createParams.room_alias_name = this.bridge.AS.getAliasLocalpartForSuffix(`${data.puppetId}_${util_1.Util.str2mxid(data.roomId)}`); | ||
} | ||
mxid = yield client.createRoom(createParams); | ||
yield this.chanStore.setChanOp(mxid, yield client.getUserId()); | ||
chan = this.chanStore.newData(mxid, data.roomId, data.puppetId); | ||
created = true; | ||
} | ||
log.info("Channel doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createChan) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = yield this.bridge.hooks.createChan(data); | ||
if (newData && newData.puppetId === data.puppetId && newData.roomId === data.roomId) { | ||
data = newData; | ||
else { | ||
update.name = data.name !== undefined && data.name !== chan.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== chan.avatarUrl; | ||
update.topic = data.topic !== undefined && data.topic !== chan.topic; | ||
mxid = chan.mxid; | ||
// set new client for potential updates | ||
const newClient = yield this.getChanOp(mxid); | ||
if (newClient) { | ||
client = newClient; | ||
} | ||
else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
} | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
yield client.sendStateEvent(mxid, "m.room.name", "", { name: data.name }); | ||
chan.name = data.name; | ||
} | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile(client, data, chan.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
chan.avatarUrl = data.avatarUrl; | ||
chan.avatarHash = hash; | ||
chan.avatarMxc = mxcUrl; | ||
yield client.sendStateEvent(mxid, "m.room.avatar", "", { url: chan.avatarMxc }); | ||
} | ||
} | ||
log.verbose("Creation data:", data); | ||
log.verbose("Initial invites:", invites); | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
update.topic = data.topic ? true : false; | ||
// ooookay, we need to create this channel | ||
const createParams = { | ||
visibility: "private", | ||
preset: "private_chat", | ||
power_level_content_override: { | ||
notifications: { | ||
room: 0, | ||
}, | ||
}, | ||
is_direct: data.isDirect, | ||
invite: invites, | ||
}; | ||
if (!data.isDirect) { | ||
// we also want to set an alias for later reference | ||
createParams.room_alias_name = this.bridge.AS.getAliasLocalpartForSuffix(`${data.puppetId}_${util_1.Util.str2mxid(data.roomId)}`); | ||
if (update.topic) { | ||
log.verbose("updating topic"); | ||
yield client.sendStateEvent(mxid, "m.room.topic", "", { topic: data.topic }); | ||
chan.topic = data.topic; | ||
} | ||
mxid = yield client.createRoom(createParams); | ||
yield this.chanStore.setChanOp(mxid, yield client.getUserId()); | ||
chan = this.chanStore.newData(mxid, data.roomId, data.puppetId); | ||
created = true; | ||
} | ||
else { | ||
update.name = data.name !== undefined && data.name !== chan.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== chan.avatarUrl; | ||
update.topic = data.topic !== undefined && data.topic !== chan.topic; | ||
mxid = chan.mxid; | ||
// set new client for potential updates | ||
const newClient = yield this.getChanOp(mxid); | ||
if (newClient) { | ||
client = newClient; | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
} | ||
} | ||
} | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
yield client.sendStateEvent(mxid, "m.room.name", "", { name: data.name }); | ||
chan.name = data.name; | ||
} | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile(client, data, chan.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
chan.avatarUrl = data.avatarUrl; | ||
chan.avatarHash = hash; | ||
chan.avatarMxc = mxcUrl; | ||
yield client.sendStateEvent(mxid, "m.room.avatar", "", { url: chan.avatarMxc }); | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
yield this.chanStore.set(chan); | ||
} | ||
this.mxidLock.release(lockKey); | ||
log.verbose("Returning mxid"); | ||
return { mxid, created }; | ||
} | ||
if (update.topic) { | ||
log.verbose("updating topic"); | ||
yield client.sendStateEvent(mxid, "m.room.topic", "", { topic: data.topic }); | ||
chan.topic = data.topic; | ||
catch (err) { | ||
log.error("Error fetching mxid:", err); | ||
this.mxidLock.release(lockKey); | ||
throw err; | ||
} | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
} | ||
} | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
yield this.chanStore.set(chan); | ||
} | ||
this.mxidLock.release(lockKey); | ||
return { mxid, created }; | ||
}); | ||
@@ -176,0 +184,0 @@ } |
@@ -242,2 +242,3 @@ "use strict"; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
log.verbose(`Setting user presence for userId=${user.userId} to ${presence}`); | ||
const client = yield this.userSync.getClient(user); | ||
@@ -250,2 +251,3 @@ const userId = yield client.getUserId(); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
log.verbose(`Setting user status for userId=${user.userId} to ${status}`); | ||
const client = yield this.userSync.getClient(user); | ||
@@ -258,2 +260,3 @@ const userId = yield client.getUserId(); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
log.verbose(`Setting user typing for userId=${params.user.userId} in roomId=${params.chan.roomId} to ${typing}`); | ||
const ret = yield this.maybePrepareSend(params); | ||
@@ -476,3 +479,3 @@ if (!ret) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const client = yield this.userSync.getClient(params.user); | ||
log.verbose(`Maybe preparing send parameters`, params); | ||
const mxid = yield this.chanSync.maybeGetMxid(params.chan); | ||
@@ -482,2 +485,3 @@ if (!mxid) { | ||
} | ||
const client = yield this.userSync.getClient(params.user); | ||
return { client, mxid }; | ||
@@ -839,6 +843,10 @@ }); | ||
log.info(`Got room query for alias ${alias}`); | ||
// get room ID and check if ti is valid | ||
// we deny room creation and then create it later on ourself | ||
yield createRoom(false); | ||
if (!this.hooks.createChan) { | ||
return; | ||
} | ||
// get room ID and check if it is valid | ||
const parts = this.chanSync.getPartsFromMxid(alias); | ||
if (!parts) { | ||
yield createRoom(false); | ||
return; | ||
@@ -849,7 +857,9 @@ } | ||
if (!puppet) { | ||
yield createRoom(false); | ||
return; | ||
} | ||
// reject the lookup and create the room with invite manually instead | ||
yield createRoom(false); | ||
// check if this is a valid room at all | ||
const room = yield this.hooks.createChan(parts); | ||
if (!room || room.puppetId !== parts.puppetId || room.roomId !== parts.roomId || room.isDirect) { | ||
return; | ||
} | ||
// this will also only create the room if it doesn't exist already | ||
@@ -856,0 +866,0 @@ yield this.chanSync.getMxid(parts, undefined, [puppet.puppetMxid]); |
@@ -43,2 +43,3 @@ "use strict"; | ||
// first we look if we can puppet this user to the matrix side | ||
log.silly("Start of getClient request"); | ||
const puppetData = yield this.bridge.provisioner.get(data.puppetId); | ||
@@ -53,70 +54,79 @@ if (puppetData && puppetData.userId === data.userId) { | ||
// now we fetch the ghost client | ||
yield this.clientLock.wait(data.userId); | ||
this.clientLock.set(data.userId); | ||
const lockKey = `${data.puppetId};${data.userId}`; | ||
yield this.clientLock.wait(lockKey); | ||
this.clientLock.set(lockKey); | ||
log.info("Fetching client for " + data.userId); | ||
let user = yield this.userStore.get(data.puppetId, data.userId); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
}; | ||
let doUpdate = false; | ||
if (!user) { | ||
log.info("User doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createUser) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = yield this.bridge.hooks.createUser(data); | ||
if (newData && newData.userId === data.userId && newData.puppetId === data.puppetId) { | ||
data = newData; | ||
try { | ||
let user = yield this.userStore.get(data.puppetId, data.userId); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
}; | ||
let doUpdate = false; | ||
if (!user) { | ||
log.info("User doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createUser) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = yield this.bridge.hooks.createUser(data); | ||
if (newData && newData.userId === data.userId && newData.puppetId === data.puppetId) { | ||
data = newData; | ||
} | ||
else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
} | ||
} | ||
else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
} | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
user = this.userStore.newData(data.puppetId, data.userId); | ||
} | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
user = this.userStore.newData(data.puppetId, data.userId); | ||
} | ||
else { | ||
update.name = data.name !== undefined && data.name !== user.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== user.avatarUrl; | ||
} | ||
const intent = this.bridge.AS.getIntentForSuffix(`${data.puppetId}_${util_1.Util.str2mxid(data.userId)}`); | ||
yield intent.ensureRegistered(); | ||
const client = intent.underlyingClient; | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
// we *don't* await here as setting the name might take a | ||
// while due to updating all those m.room.member events, we can do that in the BG | ||
// tslint:disable-next-line:no-floating-promises | ||
client.setDisplayName(data.name || ""); | ||
user.name = data.name; | ||
} | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile(client, data, user.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
user.avatarUrl = data.avatarUrl; | ||
user.avatarHash = hash; | ||
user.avatarMxc = mxcUrl; | ||
// we *don't* await here as that can take rather long | ||
// and we might as well do this in the background | ||
else { | ||
update.name = data.name !== undefined && data.name !== user.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== user.avatarUrl; | ||
} | ||
const intent = this.bridge.AS.getIntentForSuffix(`${data.puppetId}_${util_1.Util.str2mxid(data.userId)}`); | ||
yield intent.ensureRegistered(); | ||
const client = intent.underlyingClient; | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
// we *don't* await here as setting the name might take a | ||
// while due to updating all those m.room.member events, we can do that in the BG | ||
// tslint:disable-next-line:no-floating-promises | ||
client.setAvatarUrl(user.avatarMxc || ""); | ||
client.setDisplayName(data.name || ""); | ||
user.name = data.name; | ||
} | ||
} | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile(client, data, user.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
user.avatarUrl = data.avatarUrl; | ||
user.avatarHash = hash; | ||
user.avatarMxc = mxcUrl; | ||
// we *don't* await here as that can take rather long | ||
// and we might as well do this in the background | ||
// tslint:disable-next-line:no-floating-promises | ||
client.setAvatarUrl(user.avatarMxc || ""); | ||
} | ||
} | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
} | ||
} | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
yield this.userStore.set(user); | ||
} | ||
this.clientLock.release(lockKey); | ||
log.verbose("Returning client"); | ||
return client; | ||
} | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
yield this.userStore.set(user); | ||
catch (err) { | ||
log.error("Error fetching client:", err); | ||
this.clientLock.release(lockKey); | ||
throw err; | ||
} | ||
this.clientLock.release(data.userId); | ||
return client; | ||
}); | ||
@@ -123,0 +133,0 @@ } |
{ | ||
"name": "mx-puppet-bridge", | ||
"version": "0.0.8", | ||
"version": "0.0.9", | ||
"description": "Matrix Puppeting Bridge library", | ||
@@ -5,0 +5,0 @@ "repository": { |
@@ -115,3 +115,3 @@ import { PuppetBridge } from "./puppetbridge"; | ||
for (const u of users) { | ||
const nameHtml = escapeHtml(u.name); | ||
const nameHtml = escapeHtml(u.name); | ||
if (u.category) { | ||
@@ -152,3 +152,3 @@ reply += `${u.name}:\n`; | ||
for (const c of chans) { | ||
const nameHtml = escapeHtml(c.name); | ||
const nameHtml = escapeHtml(c.name); | ||
if (c.category) { | ||
@@ -173,3 +173,4 @@ reply += `${c.name}:\n`; | ||
default: | ||
await this.sendMessage(roomId, `Available commands: help, list, link, unlink, setmatrixtoken, listusers, listchannels`); | ||
await this.sendMessage(roomId, "Available commands: help, list, link, " + | ||
"unlink, setmatrixtoken, listusers, listchannels"); | ||
} | ||
@@ -176,0 +177,0 @@ } |
@@ -82,124 +82,132 @@ import { PuppetBridge } from "./puppetbridge"; | ||
log.info(`Fetching mxid for roomId ${data.roomId} and puppetId ${data.puppetId}`); | ||
if (!client) { | ||
client = this.bridge.botIntent.underlyingClient; | ||
} | ||
let chan = await this.chanStore.getByRemote(data.puppetId, data.roomId); | ||
log.silly(chan); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
topic: false, | ||
}; | ||
let mxid = ""; | ||
let doUpdate = false; | ||
let created = false; | ||
if (!chan) { | ||
if (!doCreate) { | ||
this.mxidLock.release(lockKey); | ||
return { | ||
mxid: "", | ||
created: false, | ||
}; | ||
try { | ||
if (!client) { | ||
client = this.bridge.botIntent.underlyingClient; | ||
} | ||
log.info("Channel doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createChan) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = await this.bridge.hooks.createChan(data); | ||
if (newData && newData.puppetId === data.puppetId && newData.roomId === data.roomId) { | ||
data = newData; | ||
} else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
let chan = await this.chanStore.getByRemote(data.puppetId, data.roomId); | ||
log.silly(chan); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
topic: false, | ||
}; | ||
let mxid = ""; | ||
let doUpdate = false; | ||
let created = false; | ||
if (!chan) { | ||
if (!doCreate) { | ||
this.mxidLock.release(lockKey); | ||
return { | ||
mxid: "", | ||
created: false, | ||
}; | ||
} | ||
} | ||
log.verbose("Creation data:", data); | ||
log.verbose("Initial invites:", invites); | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
update.topic = data.topic ? true : false; | ||
// ooookay, we need to create this channel | ||
const createParams = { | ||
visibility: "private", | ||
preset: "private_chat", | ||
power_level_content_override: { | ||
notifications: { | ||
room: 0, | ||
log.info("Channel doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createChan) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = await this.bridge.hooks.createChan(data); | ||
if (newData && newData.puppetId === data.puppetId && newData.roomId === data.roomId) { | ||
data = newData; | ||
} else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
} | ||
} | ||
log.verbose("Creation data:", data); | ||
log.verbose("Initial invites:", invites); | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
update.topic = data.topic ? true : false; | ||
// ooookay, we need to create this channel | ||
const createParams = { | ||
visibility: "private", | ||
preset: "private_chat", | ||
power_level_content_override: { | ||
notifications: { | ||
room: 0, | ||
}, | ||
}, | ||
}, | ||
is_direct: data.isDirect, | ||
invite: invites, | ||
} as any; | ||
if (!data.isDirect) { | ||
// we also want to set an alias for later reference | ||
createParams.room_alias_name = this.bridge.AS.getAliasLocalpartForSuffix( | ||
`${data.puppetId}_${Util.str2mxid(data.roomId)}`); | ||
} | ||
mxid = await client!.createRoom(createParams); | ||
await this.chanStore.setChanOp(mxid, await client!.getUserId()); | ||
chan = this.chanStore.newData(mxid, data.roomId, data.puppetId); | ||
created = true; | ||
} else { | ||
update.name = data.name !== undefined && data.name !== chan.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== chan.avatarUrl; | ||
update.topic = data.topic !== undefined && data.topic !== chan.topic; | ||
mxid = chan.mxid; | ||
is_direct: data.isDirect, | ||
invite: invites, | ||
} as any; | ||
if (!data.isDirect) { | ||
// we also want to set an alias for later reference | ||
createParams.room_alias_name = this.bridge.AS.getAliasLocalpartForSuffix( | ||
`${data.puppetId}_${Util.str2mxid(data.roomId)}`); | ||
} | ||
mxid = await client!.createRoom(createParams); | ||
await this.chanStore.setChanOp(mxid, await client!.getUserId()); | ||
chan = this.chanStore.newData(mxid, data.roomId, data.puppetId); | ||
created = true; | ||
} else { | ||
update.name = data.name !== undefined && data.name !== chan.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== chan.avatarUrl; | ||
update.topic = data.topic !== undefined && data.topic !== chan.topic; | ||
mxid = chan.mxid; | ||
// set new client for potential updates | ||
const newClient = await this.getChanOp(mxid); | ||
if (newClient) { | ||
client = newClient; | ||
// set new client for potential updates | ||
const newClient = await this.getChanOp(mxid); | ||
if (newClient) { | ||
client = newClient; | ||
} | ||
} | ||
} | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
await client!.sendStateEvent( | ||
mxid, | ||
"m.room.name", | ||
"", | ||
{ name: data.name }, | ||
); | ||
chan.name = data.name; | ||
} | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile(client!, data, chan.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
chan.avatarUrl = data.avatarUrl; | ||
chan.avatarHash = hash; | ||
chan.avatarMxc = mxcUrl; | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
await client!.sendStateEvent( | ||
mxid, | ||
"m.room.avatar", | ||
"m.room.name", | ||
"", | ||
{ url: chan.avatarMxc }, | ||
{ name: data.name }, | ||
); | ||
chan.name = data.name; | ||
} | ||
} | ||
if (update.topic) { | ||
log.verbose("updating topic"); | ||
await client!.sendStateEvent( | ||
mxid, | ||
"m.room.topic", | ||
"", | ||
{ topic: data.topic }, | ||
); | ||
chan.topic = data.topic; | ||
} | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile(client!, data, chan.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
chan.avatarUrl = data.avatarUrl; | ||
chan.avatarHash = hash; | ||
chan.avatarMxc = mxcUrl; | ||
await client!.sendStateEvent( | ||
mxid, | ||
"m.room.avatar", | ||
"", | ||
{ url: chan.avatarMxc }, | ||
); | ||
} | ||
} | ||
if (update.topic) { | ||
log.verbose("updating topic"); | ||
await client!.sendStateEvent( | ||
mxid, | ||
"m.room.topic", | ||
"", | ||
{ topic: data.topic }, | ||
); | ||
chan.topic = data.topic; | ||
} | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
} | ||
} | ||
} | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
await this.chanStore.set(chan); | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
await this.chanStore.set(chan); | ||
} | ||
this.mxidLock.release(lockKey); | ||
log.verbose("Returning mxid"); | ||
return { mxid, created }; | ||
} catch (err) { | ||
log.error("Error fetching mxid:", err); | ||
this.mxidLock.release(lockKey); | ||
throw err; | ||
} | ||
this.mxidLock.release(lockKey); | ||
return { mxid, created }; | ||
} | ||
@@ -206,0 +214,0 @@ |
@@ -361,2 +361,3 @@ import * as fs from "fs"; | ||
public async setUserPresence(user: IRemoteUser, presence: MatrixPresence) { | ||
log.verbose(`Setting user presence for userId=${user.userId} to ${presence}`); | ||
const client = await this.userSync.getClient(user); | ||
@@ -368,2 +369,3 @@ const userId = await client.getUserId(); | ||
public async setUserStatus(user: IRemoteUser, status: string) { | ||
log.verbose(`Setting user status for userId=${user.userId} to ${status}`); | ||
const client = await this.userSync.getClient(user); | ||
@@ -375,2 +377,3 @@ const userId = await client.getUserId(); | ||
public async setUserTyping(params: IReceiveParams, typing: boolean) { | ||
log.verbose(`Setting user typing for userId=${params.user.userId} in roomId=${params.chan.roomId} to ${typing}`); | ||
const ret = await this.maybePrepareSend(params); | ||
@@ -578,3 +581,3 @@ if (!ret) { | ||
private async maybePrepareSend(params: IReceiveParams): Promise<ISendInfo | null> { | ||
const client = await this.userSync.getClient(params.user); | ||
log.verbose(`Maybe preparing send parameters`, params); | ||
const mxid = await this.chanSync.maybeGetMxid(params.chan); | ||
@@ -584,2 +587,3 @@ if (!mxid) { | ||
} | ||
const client = await this.userSync.getClient(params.user); | ||
return { client, mxid }; | ||
@@ -936,6 +940,10 @@ } | ||
log.info(`Got room query for alias ${alias}`); | ||
// get room ID and check if ti is valid | ||
// we deny room creation and then create it later on ourself | ||
await createRoom(false); | ||
if (!this.hooks.createChan) { | ||
return; | ||
} | ||
// get room ID and check if it is valid | ||
const parts = this.chanSync.getPartsFromMxid(alias); | ||
if (!parts) { | ||
await createRoom(false); | ||
return; | ||
@@ -946,7 +954,11 @@ } | ||
if (!puppet) { | ||
await createRoom(false); | ||
return; | ||
} | ||
// reject the lookup and create the room with invite manually instead | ||
await createRoom(false); | ||
// check if this is a valid room at all | ||
const room = await this.hooks.createChan(parts); | ||
if (!room || room.puppetId !== parts.puppetId || room.roomId !== parts.roomId || room.isDirect) { | ||
return; | ||
} | ||
// this will also only create the room if it doesn't exist already | ||
@@ -953,0 +965,0 @@ await this.chanSync.getMxid(parts, undefined, [puppet.puppetMxid]); |
@@ -49,2 +49,3 @@ import { PuppetBridge } from "./puppetbridge"; | ||
// first we look if we can puppet this user to the matrix side | ||
log.silly("Start of getClient request"); | ||
const puppetData = await this.bridge.provisioner.get(data.puppetId); | ||
@@ -60,71 +61,79 @@ if (puppetData && puppetData.userId === data.userId) { | ||
// now we fetch the ghost client | ||
await this.clientLock.wait(data.userId); | ||
this.clientLock.set(data.userId); | ||
const lockKey = `${data.puppetId};${data.userId}`; | ||
await this.clientLock.wait(lockKey); | ||
this.clientLock.set(lockKey); | ||
log.info("Fetching client for " + data.userId); | ||
let user = await this.userStore.get(data.puppetId, data.userId); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
}; | ||
let doUpdate = false; | ||
if (!user) { | ||
log.info("User doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createUser) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = await this.bridge.hooks.createUser(data); | ||
if (newData && newData.userId === data.userId && newData.puppetId === data.puppetId) { | ||
data = newData; | ||
} else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
try { | ||
let user = await this.userStore.get(data.puppetId, data.userId); | ||
const update = { | ||
name: false, | ||
avatar: false, | ||
}; | ||
let doUpdate = false; | ||
if (!user) { | ||
log.info("User doesn't exist yet, creating entry..."); | ||
doUpdate = true; | ||
// let's fetch the create data via hook | ||
if (this.bridge.hooks.createUser) { | ||
log.verbose("Fetching new override data..."); | ||
const newData = await this.bridge.hooks.createUser(data); | ||
if (newData && newData.userId === data.userId && newData.puppetId === data.puppetId) { | ||
data = newData; | ||
} else { | ||
log.warn("Override data is malformed! Old data:", data, "New data:", newData); | ||
} | ||
} | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
user = this.userStore.newData(data.puppetId, data.userId); | ||
} else { | ||
update.name = data.name !== undefined && data.name !== user.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== user.avatarUrl; | ||
} | ||
update.name = data.name ? true : false; | ||
update.avatar = data.avatarUrl ? true : false; | ||
user = this.userStore.newData(data.puppetId, data.userId); | ||
} else { | ||
update.name = data.name !== undefined && data.name !== user.name; | ||
update.avatar = data.avatarUrl !== undefined && data.avatarUrl !== user.avatarUrl; | ||
} | ||
const intent = this.bridge.AS.getIntentForSuffix(`${data.puppetId}_${Util.str2mxid(data.userId)}`); | ||
await intent.ensureRegistered(); | ||
const client = intent.underlyingClient; | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
// we *don't* await here as setting the name might take a | ||
// while due to updating all those m.room.member events, we can do that in the BG | ||
// tslint:disable-next-line:no-floating-promises | ||
client.setDisplayName(data.name || ""); | ||
user.name = data.name; | ||
} | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile(client, data, user.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
user.avatarUrl = data.avatarUrl; | ||
user.avatarHash = hash; | ||
user.avatarMxc = mxcUrl; | ||
// we *don't* await here as that can take rather long | ||
// and we might as well do this in the background | ||
const intent = this.bridge.AS.getIntentForSuffix(`${data.puppetId}_${Util.str2mxid(data.userId)}`); | ||
await intent.ensureRegistered(); | ||
const client = intent.underlyingClient; | ||
if (update.name) { | ||
log.verbose("Updating name"); | ||
// we *don't* await here as setting the name might take a | ||
// while due to updating all those m.room.member events, we can do that in the BG | ||
// tslint:disable-next-line:no-floating-promises | ||
client.setAvatarUrl(user.avatarMxc || ""); | ||
client.setDisplayName(data.name || ""); | ||
user.name = data.name; | ||
} | ||
} | ||
if (update.avatar || data.avatarBuffer) { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile(client, data, user.avatarHash); | ||
if (updateAvatar) { | ||
update.avatar = true; | ||
user.avatarUrl = data.avatarUrl; | ||
user.avatarHash = hash; | ||
user.avatarMxc = mxcUrl; | ||
// we *don't* await here as that can take rather long | ||
// and we might as well do this in the background | ||
// tslint:disable-next-line:no-floating-promises | ||
client.setAvatarUrl(user.avatarMxc || ""); | ||
} | ||
} | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
for (const k of Object.keys(update)) { | ||
if (update[k]) { | ||
doUpdate = true; | ||
break; | ||
} | ||
} | ||
} | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
await this.userStore.set(user); | ||
} | ||
if (doUpdate) { | ||
log.verbose("Storing update to DB"); | ||
await this.userStore.set(user); | ||
} | ||
this.clientLock.release(data.userId); | ||
this.clientLock.release(lockKey); | ||
return client; | ||
log.verbose("Returning client"); | ||
return client; | ||
} catch (err) { | ||
log.error("Error fetching client:", err); | ||
this.clientLock.release(lockKey); | ||
throw err; | ||
} | ||
} | ||
@@ -131,0 +140,0 @@ |
278161
7379