Skip to content

Feat: Implement the file event parsing section #27

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

Merged
merged 2 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lagrange/client/message/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

from . import elems
from .types import Element
from lagrange.utils.binary.reader import Reader
from lagrange.utils.binary.protobuf import proto_encode
from lagrange.pb.message.rich_text.elems import GroupFileExtra, FileExtra
from lagrange.pb.highway.comm import MsgInfo

if TYPE_CHECKING:
Expand Down Expand Up @@ -36,6 +38,18 @@ def parse_friend_info(pkg: MsgPushBody) -> Tuple[int, str, int, str]:


async def parse_msg_new(client: "Client", pkg: MsgPushBody) -> Sequence[Element]:
if not pkg.message or not pkg.message.body:
if pkg.content_head.sub_type == 4:
data = FileExtra.decode(pkg.message.buf2)
return [
elems.File.pri_paste_build(
file_size=data.file.file_size,
file_name=data.file.file_name,
file_md5=data.file.file_md5,
file_uuid=data.file.file_uuid,
file_hash=data.file.file_hash,
)
]
rich: RichText = pkg.message.body
if rich.ptt:
ptt = rich.ptt
Expand Down Expand Up @@ -166,6 +180,21 @@ async def parse_msg_new(client: "Client", pkg: MsgPushBody) -> Sequence[Element]
qmsg=None,
)
)
elif raw.trans_elem:
elem_type, trans = raw.trans_elem.elem_type, raw.trans_elem.elem_value
if elem_type == 24:
reader = Reader(trans)
reader.read_bytes(1)
data = reader.read_bytes_with_length("u16", False)
file_extra = GroupFileExtra.decode(data)
msg_chain.append(
elems.File.grp_paste_build(
file_size=file_extra.inner.info.file_size,
file_name=file_extra.inner.info.file_name,
file_md5=file_extra.inner.info.file_md5,
file_id=file_extra.inner.info.file_id
)
)
elif raw.rich_msg:
service = raw.rich_msg
if service.template:
Expand Down
34 changes: 34 additions & 0 deletions lagrange/client/message/elems.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,37 @@ class MarketFace(Text):
def url(self) -> str:
pic_id = self.face_id.hex()
return f"https://i.gtimg.cn/club/item/parcel/item/{pic_id[:2]}/{pic_id}/{self.width}x{self.height}.png"


@dataclass
class File(Text):
file_size: int
file_name: str
file_md5: bytes
file_url: Optional[str]
file_id: Optional[str] # only in group
file_uuid: Optional[str] # only in private
file_hash: Optional[str]

@classmethod
def _paste_build(cls, file_size: int, file_name: str,
file_md5: bytes, file_id: Optional[str] = None,
file_uuid: Optional[str] = None, file_hash: Optional[str] = None) -> "File":
return cls(
text=f"[file:{file_name}]",
file_size=file_size,
file_name=file_name,
file_md5=file_md5,
file_url=None,
file_id=file_id,
file_uuid=file_uuid,
file_hash=file_hash,
)

@classmethod
def grp_paste_build(cls, file_size: int, file_name: str, file_md5: bytes, file_id: str) -> "File":
return cls._paste_build(file_size, file_name, file_md5, file_id=file_id)

@classmethod
def pri_paste_build(cls, file_size: int, file_name: str, file_md5: bytes, file_uuid: str, file_hash: str) -> "File":
return cls._paste_build(file_size, file_name, file_md5, file_uuid=file_uuid, file_hash=file_hash)
6 changes: 3 additions & 3 deletions lagrange/client/server_push/msg.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ async def msg_push_handler(client: "Client", sso: SSOPacket):
logger.debug("msg_push received, type: {}.{}".format(typ, sub_typ))
if typ == 82: # grp msg
return await parse_grp_msg(client, pkg)
elif typ == 166: # frd msg
elif typ in [166, 529]: # frd msg
return await parse_friend_msg(client, pkg)
elif typ == 33: # member joined
pb = MemberChanged.decode(pkg.message.buf2)
Expand Down Expand Up @@ -88,8 +88,8 @@ async def msg_push_handler(client: "Client", sso: SSOPacket):
return GroupMemberJoinRequest(
grp_id=inn.grp_id, uid=inn.uid, invitor_uid=inn.invitor_uid
)
elif typ == 0x210: # frd event
logger.debug("unhandled friend event: %s" % pkg)
elif typ == 0x210: # friend event / group file upload notice event
logger.debug("unhandled friend event / group file upload notice event: %s" % pkg) # TODO: paste
elif typ == 0x2DC: # grp event, 732
if sub_typ == 20: # nudge and group_sign(群打卡)
if pkg.message:
Expand Down
48 changes: 48 additions & 0 deletions lagrange/pb/message/rich_text/elems.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,51 @@ class VideoFile(ProtoStruct):
thumb_width: int = proto_field(16)
thumb_height: int = proto_field(17)
# reserve on field 24?


class NotOnlineFile(ProtoStruct):
file_type: Optional[int] = proto_field(1)
# sig: Optional[bytes] = proto_field(2)
file_uuid: Optional[str] = proto_field(3)
file_md5: Optional[bytes] = proto_field(4)
file_name: Optional[str] = proto_field(5)
file_size: Optional[int] = proto_field(6)
# note: Optional[bytes] = proto_field(7)
# reserved: Optional[int] = proto_field(8)
subcmd: Optional[int] = proto_field(9)
# micro_cloud: Optional[int] = proto_field(10)
# bytes_file_urls: Optional[list[bytes]] = proto_field(11)
# download_flag: Optional[int] = proto_field(12)
danger_evel: Optional[int] = proto_field(50)
# life_time: Optional[int] = proto_field(51)
# upload_time: Optional[int] = proto_field(52)
# abs_file_type: Optional[int] = proto_field(53)
# client_type: Optional[int] = proto_field(54)
expire_time: Optional[int] = proto_field(55)
pb_reserve: bytes = proto_field(56)
file_hash: Optional[str] = proto_field(57)


class FileExtra(ProtoStruct):
file: NotOnlineFile = proto_field(1)


class GroupFileExtraInfo(ProtoStruct):
bus_id: int = proto_field(1)
file_id: str = proto_field(2)
file_size: int = proto_field(3)
file_name: str = proto_field(4)
f5: int = proto_field(5)
f7: str = proto_field(7)
file_md5: bytes = proto_field(8)


class GroupFileExtraInner(ProtoStruct):
info: GroupFileExtraInfo = proto_field(2)


class GroupFileExtra(ProtoStruct):
f1: int = proto_field(1)
file_name: str = proto_field(2)
display: str = proto_field(3)
inner: GroupFileExtraInner = proto_field(7)