stuff for multi person chats
This commit is contained in:
parent
a43502b45e
commit
328167c5f2
|
@ -58,6 +58,7 @@ class Config(BaseBridgeConfig):
|
|||
copy("bridge.displayname_max_length")
|
||||
|
||||
copy("bridge.initial_conversation_sync")
|
||||
copy("bridge.invite_own_puppet_to_pm")
|
||||
copy("bridge.login_shared_secret")
|
||||
copy("bridge.federate_rooms")
|
||||
copy("bridge.backfill.invite_own_puppet")
|
||||
|
|
|
@ -49,6 +49,7 @@ ReuploadedMediaInfo = NamedTuple('ReuploadedMediaInfo', mxc=Optional[ContentURI]
|
|||
|
||||
|
||||
class Portal(DBPortal, BasePortal):
|
||||
invite_own_puppet_to_pm: bool = False
|
||||
by_mxid: Dict[RoomID, 'Portal'] = {}
|
||||
by_chat_id: Dict[int, 'Portal'] = {}
|
||||
config: Config
|
||||
|
@ -77,7 +78,15 @@ class Portal(DBPortal, BasePortal):
|
|||
|
||||
@property
|
||||
def is_direct(self) -> bool:
|
||||
return self.other_user is not None
|
||||
return self.chat_id[0] == "u"
|
||||
|
||||
@property
|
||||
def is_group(self) -> bool:
|
||||
return self.chat_id[0] == "c"
|
||||
|
||||
@property
|
||||
def is_room(self) -> bool:
|
||||
return self.chat_id[0] == "r"
|
||||
|
||||
@property
|
||||
def main_intent(self) -> IntentAPI:
|
||||
|
@ -92,6 +101,7 @@ class Portal(DBPortal, BasePortal):
|
|||
cls.az = bridge.az
|
||||
cls.loop = bridge.loop
|
||||
cls.bridge = bridge
|
||||
cls.invite_own_puppet_to_pm = cls.config["bridge.invite_own_puppet_to_pm"]
|
||||
NotificationDisabler.puppet_cls = p.Puppet
|
||||
NotificationDisabler.config_enabled = cls.config["bridge.backfill.disable_notifications"]
|
||||
|
||||
|
@ -145,36 +155,54 @@ class Portal(DBPortal, BasePortal):
|
|||
self.log.debug(f"{user.mxid} left portal to {self.chat_id}")
|
||||
# TODO cleanup if empty
|
||||
|
||||
async def handle_remote_message(self, source: 'u.User', evt: Message) -> None:
|
||||
if evt.is_outgoing:
|
||||
async def _bridge_own_message_pm(self, source: 'u.User', sender: 'p.Puppet', mid: str,
|
||||
invite: bool = True) -> bool:
|
||||
if self.is_direct and sender.fbid == source.fbid and not sender.is_real_user:
|
||||
if self.invite_own_puppet_to_pm and invite:
|
||||
await self.main_intent.invite_user(self.mxid, sender.mxid)
|
||||
elif await self.az.state_store.get_membership(self.mxid,
|
||||
sender.mxid) != Membership.JOIN:
|
||||
self.log.warning(f"Ignoring own {mid} in private chat because own puppet is not in"
|
||||
" room.")
|
||||
return False
|
||||
return True
|
||||
|
||||
async def handle_remote_message(self, source: 'u.User', message: Message) -> None:
|
||||
# TODO
|
||||
if message.is_outgoing:
|
||||
if not source.intent:
|
||||
self.log.warning(f"Ignoring message {evt.id}: double puppeting isn't enabled")
|
||||
if not await self._bridge_own_message_pm(source, sender, mid, invite):
|
||||
return
|
||||
if not self.invite_own_puppet_to_pm:
|
||||
self.log.warning(f"Ignoring message {message.id}: double puppeting isn't enabled")
|
||||
return
|
||||
intent = self.main_intent
|
||||
else:
|
||||
intent = source.intent
|
||||
elif self.other_user:
|
||||
intent = (await p.Puppet.get_by_mid(self.other_user)).intent
|
||||
else:
|
||||
# TODO group chats
|
||||
self.log.warning(f"Ignoring message {evt.id}: group chats aren't supported yet")
|
||||
self.log.warning(f"Ignoring message {message.id}: group chats aren't supported yet")
|
||||
return
|
||||
|
||||
if await DBMessage.get_by_mid(evt.id):
|
||||
self.log.debug(f"Ignoring duplicate message {evt.id}")
|
||||
if await DBMessage.get_by_mid(message.id):
|
||||
self.log.debug(f"Ignoring duplicate message {message.id}")
|
||||
return
|
||||
|
||||
event_id = None
|
||||
if evt.image:
|
||||
content = await self._handle_remote_photo(source, intent, evt)
|
||||
if message.image:
|
||||
content = await self._handle_remote_photo(source, intent, message)
|
||||
if content:
|
||||
event_id = await self._send_message(intent, content, timestamp=evt.timestamp)
|
||||
if evt.text and not evt.text.isspace():
|
||||
content = TextMessageEventContent(msgtype=MessageType.TEXT, body=evt.text)
|
||||
event_id = await self._send_message(intent, content, timestamp=evt.timestamp)
|
||||
event_id = await self._send_message(intent, content, timestamp=message.timestamp)
|
||||
if message.text and not message.text.isspace():
|
||||
content = TextMessageEventContent(msgtype=MessageType.TEXT, body=message.text)
|
||||
event_id = await self._send_message(intent, content, timestamp=message.timestamp)
|
||||
if event_id:
|
||||
msg = DBMessage(mxid=event_id, mx_room=self.mxid, mid=evt.id, chat_id=self.chat_id)
|
||||
msg = DBMessage(mxid=event_id, mx_room=self.mxid, mid=message.id, chat_id=self.chat_id)
|
||||
await msg.insert()
|
||||
await self._send_delivery_receipt(event_id)
|
||||
self.log.debug(f"Handled remote message {evt.id} -> {event_id}")
|
||||
self.log.debug(f"Handled remote message {message.id} -> {event_id}")
|
||||
|
||||
async def _handle_remote_photo(self, source: 'u.User', intent: IntentAPI, message: Message
|
||||
) -> Optional[MediaMessageEventContent]:
|
||||
|
@ -200,15 +228,16 @@ class Portal(DBPortal, BasePortal):
|
|||
return ReuploadedMediaInfo(mxc, decryption_info, mime_type, file_name, len(data))
|
||||
|
||||
async def update_info(self, conv: ChatInfo) -> None:
|
||||
# TODO Not true: a single-participant chat could be a group!
|
||||
if len(conv.participants) == 1:
|
||||
if self.is_direct:
|
||||
self.other_user = conv.participants[0].id
|
||||
if self._main_intent is self.az.intent:
|
||||
self._main_intent = (await p.Puppet.get_by_mid(self.other_user)).intent
|
||||
for participant in conv.participants:
|
||||
puppet = await p.Puppet.get_by_mid(participant.id)
|
||||
await puppet.update_info(participant)
|
||||
changed = await self._update_name(conv.name)
|
||||
# TODO Consider setting no room name for non-group chats.
|
||||
# But then the LINE bot itself may appear in the title...
|
||||
changed = await self._update_name(f"{conv.name} (LINE)")
|
||||
if changed:
|
||||
await self.update_bridge_info()
|
||||
await self.update()
|
||||
|
@ -267,8 +296,10 @@ class Portal(DBPortal, BasePortal):
|
|||
|
||||
self.log.debug("Got %d messages from server", len(messages))
|
||||
async with NotificationDisabler(self.mxid, source):
|
||||
for evt in messages:
|
||||
await self.handle_remote_message(source, evt)
|
||||
for message in messages:
|
||||
# TODO
|
||||
#puppet = await p.Puppet.get_by_mid(message.)
|
||||
await self.handle_remote_message(source, message)
|
||||
self.log.info("Backfilled %d messages through %s", len(messages), source.mxid)
|
||||
|
||||
@property
|
||||
|
|
|
@ -48,6 +48,8 @@ class Message(SerializableAttrs['Message']):
|
|||
id: int
|
||||
chat_id: int
|
||||
is_outgoing: bool
|
||||
# TODO
|
||||
sender: Optional[str]
|
||||
timestamp: int = None
|
||||
text: Optional[str] = None
|
||||
image: Optional[str] = None
|
||||
|
|
|
@ -104,6 +104,7 @@ class MautrixController {
|
|||
* @property {number} id - The ID of the message. Seems to be sequential.
|
||||
* @property {number} timestamp - The unix timestamp of the message. Not very accurate.
|
||||
* @property {boolean} is_outgoing - Whether or not this user sent the message.
|
||||
* @property {null|string} sender - The ID of the user who sent the message, or null if outgoing.
|
||||
* @property {string} [text] - The text in the message.
|
||||
* @property {string} [image] - The URL to the image in the message.
|
||||
*/
|
||||
|
@ -117,10 +118,17 @@ class MautrixController {
|
|||
* @private
|
||||
*/
|
||||
_tryParseMessage(date, element) {
|
||||
const is_outgoing: element.classList.contains("mdRGT07Own")
|
||||
const messageData = {
|
||||
id: +element.getAttribute("data-local-id"),
|
||||
timestamp: date ? date.getTime() : null,
|
||||
is_outgoing: element.classList.contains("mdRGT07Own"),
|
||||
is_outgoing: is_outgoing,
|
||||
// TODO The sender's mid isn't available, so must validate their display name somehow...
|
||||
// Get it from contact list? It's always available in "#contact_wrap_friends > ul"
|
||||
// <li .mdMN02Li data-mid, title=name>
|
||||
// But what about non-friends?
|
||||
// TODO Also, sender is always there, but not actually needed for DMs
|
||||
sender: !is_outgoing ? element.querySelector(".mdRGT07Body > .mdRGT07Ttl") : null
|
||||
}
|
||||
const messageElement = element.querySelector(".mdRGT07Body > .mdRGT07Msg")
|
||||
if (messageElement.classList.contains("mdRGT07Text")) {
|
||||
|
@ -226,10 +234,8 @@ class MautrixController {
|
|||
* @return {[Participant]} - The list of participants.
|
||||
*/
|
||||
parseParticipantList(element) {
|
||||
// TODO Slice to exclude first member, which is always yourself (right?)
|
||||
// TODO Only slice if double-puppeting is enabled!
|
||||
//return Array.from(element.children).slice(1).map(child => {
|
||||
return Array.from(element.children).map(child => {
|
||||
// TODO The first member is always yourself, right?
|
||||
return Array.from(element.children).slice(1).map(child => {
|
||||
return {
|
||||
id: child.getAttribute("data-mid"),
|
||||
// TODO avatar: child.querySelector("img").src,
|
||||
|
@ -331,7 +337,6 @@ class MautrixController {
|
|||
* @private
|
||||
*/
|
||||
_observeChatListMutations(mutations) {
|
||||
/* TODO
|
||||
const changedChatIDs = new Set()
|
||||
for (const change of mutations) {
|
||||
console.debug("Chat list mutation:", change)
|
||||
|
@ -350,7 +355,6 @@ class MautrixController {
|
|||
() => console.debug("Chat list mutations dispatched"),
|
||||
err => console.error("Error dispatching chat list mutations:", err))
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -95,10 +95,8 @@ export default class MessagesPuppeteer {
|
|||
await this.page.exposeFunction("__mautrixExpiry", this._receiveExpiry.bind(this))
|
||||
await this.page.exposeFunction("__mautrixReceiveMessageID",
|
||||
id => this.sentMessageIDs.add(id))
|
||||
/* TODO
|
||||
await this.page.exposeFunction("__mautrixReceiveChanges",
|
||||
this._receiveChatListChanges.bind(this))
|
||||
*/
|
||||
await this.page.exposeFunction("__chronoParseDate", chrono.parseDate)
|
||||
|
||||
// NOTE Must *always* re-login on a browser session, so no need to check if already logged in
|
||||
|
@ -509,6 +507,7 @@ export default class MessagesPuppeteer {
|
|||
return messages.filter(msg => msg.id > minID && !this.sentMessageIDs.has(msg.id))
|
||||
}
|
||||
|
||||
// TODO
|
||||
async _processChatListChangeUnsafe(id) {
|
||||
this.updatedChats.delete(id)
|
||||
this.log("Processing change to", id)
|
||||
|
@ -535,6 +534,7 @@ export default class MessagesPuppeteer {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
_receiveChatListChanges(changes) {
|
||||
this.log("Received chat list changes:", changes)
|
||||
for (const item of changes) {
|
||||
|
|
Loading…
Reference in New Issue