Inbound file messages
This commit is contained in:
parent
c9961d5078
commit
2602e58734
|
@ -58,6 +58,7 @@ from ..types.request import (
|
|||
deserialize_result,
|
||||
ResultType,
|
||||
ResultListType,
|
||||
ResultRawType,
|
||||
RootCommandResult,
|
||||
CommandResultDoneValue
|
||||
)
|
||||
|
@ -327,6 +328,18 @@ class Client:
|
|||
await self._rpc_client.request("get_memo_ids", mxid=self.user.mxid)
|
||||
)
|
||||
|
||||
def download_file(
|
||||
self,
|
||||
channel_props: ChannelProps,
|
||||
key: str,
|
||||
) -> Awaitable[bytes]:
|
||||
return self._api_user_request_result(
|
||||
ResultRawType(bytes),
|
||||
"download_file",
|
||||
channel_props=channel_props.serialize(),
|
||||
key=key,
|
||||
)
|
||||
|
||||
def send_chat(
|
||||
self,
|
||||
channel_props: ChannelProps,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from typing import Generic, Type, TypeVar, Union, Iterable
|
||||
from typing import Generic, Type, TypeVar, Union
|
||||
|
||||
from attr import dataclass
|
||||
from enum import IntEnum
|
||||
|
@ -103,6 +103,17 @@ def ResultListType(result_type: Type[ResultType]):
|
|||
|
||||
return _ResultListType
|
||||
|
||||
def ResultRawType(result_type: Type):
|
||||
class _ResultRawType(result_type, Serializable):
|
||||
def serialize(self) -> result_type:
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, data: JSON) -> "_ResultRawType":
|
||||
return result_type(data)
|
||||
|
||||
return _ResultRawType
|
||||
|
||||
|
||||
@dataclass
|
||||
class CommandResultDoneValue(RootCommandResult, Generic[ResultType]):
|
||||
|
|
|
@ -81,7 +81,7 @@ from .kt.types.chat import Chatlog, ChatType, KnownChatType
|
|||
from .kt.types.chat.attachment import (
|
||||
Attachment,
|
||||
AudioAttachment,
|
||||
#FileAttachment,
|
||||
FileAttachment,
|
||||
MediaAttachment,
|
||||
MultiPhotoAttachment,
|
||||
PhotoAttachment,
|
||||
|
@ -223,7 +223,7 @@ class Portal(DBPortal, BasePortal):
|
|||
KnownChatType.MULTIPHOTO: cls._handle_kakaotalk_multiphoto,
|
||||
KnownChatType.VIDEO: cls._handle_kakaotalk_video,
|
||||
KnownChatType.AUDIO: cls._handle_kakaotalk_audio,
|
||||
#KnownChatType.FILE: cls._handle_kakaotalk_file,
|
||||
KnownChatType.FILE: cls._handle_kakaotalk_file,
|
||||
16385: cls._handle_kakaotalk_deleted,
|
||||
}
|
||||
|
||||
|
@ -436,7 +436,7 @@ class Portal(DBPortal, BasePortal):
|
|||
power_levels.set_user_level(demoter_id, orig_power_levels[demoter_id])
|
||||
|
||||
@classmethod
|
||||
async def _reupload_kakaotalk_file(
|
||||
async def _reupload_kakaotalk_file_from_url(
|
||||
cls,
|
||||
url: str,
|
||||
source: u.User,
|
||||
|
@ -457,6 +457,28 @@ class Portal(DBPortal, BasePortal):
|
|||
if length > cls.matrix.media_config.upload_size:
|
||||
raise ValueError("File not available: too large")
|
||||
data = await resp.read()
|
||||
return await cls._reupload_kakaotalk_file_from_bytes(
|
||||
data,
|
||||
intent,
|
||||
filename=filename,
|
||||
mimetype=mimetype,
|
||||
encrypt=encrypt,
|
||||
find_size=find_size,
|
||||
convert_audio=convert_audio,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def _reupload_kakaotalk_file_from_bytes(
|
||||
cls,
|
||||
data: bytes,
|
||||
intent: IntentAPI,
|
||||
*,
|
||||
filename: str | None = None,
|
||||
mimetype: str | None = None,
|
||||
encrypt: bool = False,
|
||||
find_size: bool = False,
|
||||
convert_audio: bool = False,
|
||||
) -> tuple[ContentURI, FileInfo | VideoInfo | AudioInfo | ImageInfo, EncryptedFile | None]:
|
||||
if not mimetype:
|
||||
mimetype = magic.mimetype(data)
|
||||
if convert_audio and mimetype != "audio/ogg":
|
||||
|
@ -1610,22 +1632,6 @@ class Portal(DBPortal, BasePortal):
|
|||
**kwargs
|
||||
))
|
||||
|
||||
""" TODO Find what auth is required for reading file contents
|
||||
def _handle_kakaotalk_file(
|
||||
self,
|
||||
attachment: FileAttachment,
|
||||
**kwargs
|
||||
) -> Awaitable[list[EventID]]:
|
||||
return asyncio.gather(self._handle_kakaotalk_media(
|
||||
attachment,
|
||||
FileInfo(
|
||||
size=attachment.size,
|
||||
),
|
||||
MessageType.FILE,
|
||||
**kwargs
|
||||
))
|
||||
"""
|
||||
|
||||
async def _handle_kakaotalk_media(
|
||||
self,
|
||||
attachment: MediaAttachment,
|
||||
|
@ -1638,7 +1644,7 @@ class Portal(DBPortal, BasePortal):
|
|||
chat_text: str | None,
|
||||
**_
|
||||
) -> EventID:
|
||||
mxc, additional_info, decryption_info = await self._reupload_kakaotalk_file(
|
||||
mxc, additional_info, decryption_info = await self._reupload_kakaotalk_file_from_url(
|
||||
attachment.url,
|
||||
source,
|
||||
intent,
|
||||
|
@ -1653,6 +1659,27 @@ class Portal(DBPortal, BasePortal):
|
|||
)
|
||||
return await self._send_message(intent, content, timestamp=timestamp)
|
||||
|
||||
async def _handle_kakaotalk_file(
|
||||
self,
|
||||
source: u.User,
|
||||
intent: IntentAPI,
|
||||
attachment: FileAttachment,
|
||||
timestamp: int,
|
||||
chat_text: str | None,
|
||||
**_
|
||||
) -> list[EventID]:
|
||||
data = await source.client.download_file(self.channel_props, attachment.k)
|
||||
mxc, info, decryption_info = await self._reupload_kakaotalk_file_from_bytes(
|
||||
data,
|
||||
intent,
|
||||
filename=attachment.name,
|
||||
encrypt=self.encrypted,
|
||||
)
|
||||
content = MediaMessageEventContent(
|
||||
url=mxc, file=decryption_info, msgtype=MessageType.FILE, body=chat_text or "", info=info
|
||||
)
|
||||
return [await self._send_message(intent, content, timestamp=timestamp)]
|
||||
|
||||
async def handle_kakaotalk_chat_delete(
|
||||
self,
|
||||
sender: p.Puppet,
|
||||
|
|
|
@ -281,7 +281,7 @@ class RPCClient:
|
|||
break
|
||||
except asyncio.LimitOverrunError as e:
|
||||
self.log.warning(f"Buffer overrun: {e}")
|
||||
line += await self._reader.read(self._reader._limit)
|
||||
line += await self._reader.read(e.consumed)
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
if not line:
|
||||
|
|
|
@ -23,6 +23,7 @@ import {
|
|||
KnownAuthStatusCode,
|
||||
util,
|
||||
} from "node-kakao"
|
||||
import { ReadStreamUtil } from "node-kakao/stream"
|
||||
/** @typedef {import("node-kakao").OAuthCredential} OAuthCredential */
|
||||
/** @typedef {import("node-kakao").ChannelType} ChannelType */
|
||||
/** @typedef {import("node-kakao").ReplyAttachment} ReplyAttachment */
|
||||
|
@ -824,6 +825,21 @@ export default class PeerClient {
|
|||
return channelIds
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} req
|
||||
* @param {string} req.mxid
|
||||
* @param {ChannelProps} req.channel_props
|
||||
* @param {string} req.key
|
||||
*/
|
||||
downloadFile = async (req) => {
|
||||
const talkChannel = await this.#getUserChannel(req.mxid, req.channel_props)
|
||||
const res = await talkChannel.downloadMedia({ key: req.key }, KnownChatType.FILE)
|
||||
if (!res.success) return res
|
||||
|
||||
const data = await ReadStreamUtil.all(res.result)
|
||||
return makeCommandResult(Array.from(data))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} req
|
||||
* @param {string} req.mxid
|
||||
|
@ -1048,6 +1064,7 @@ export default class PeerClient {
|
|||
list_friends: this.listFriends,
|
||||
get_friend_dm_id: req => this.getFriendProperty(req, "directChatId"),
|
||||
get_memo_ids: this.getMemoIds,
|
||||
download_file: this.downloadFile,
|
||||
send_chat: this.sendChat,
|
||||
send_media: this.sendMedia,
|
||||
delete_chat: this.deleteChat,
|
||||
|
|
Loading…
Reference in New Issue