ForcePilot/backend/package/yuxi/channels/adapters/irc/splits.py
Kris 2dd1a075f2 feat(irc): 实现完整的IRC适配器基础功能模块
新增IRC协议相关的全套工具模块,包括:
- 核心协议解析与CTCP处理
- 消息发送缓存与文本 sanitize
- 账号配置管理与运行时状态
- 命令处理与权限控制
- 服务发现与诊断工具
- 多账号网关与配置加载
2026-05-12 00:45:10 +08:00

124 lines
3.0 KiB
Python

from __future__ import annotations
def split_utf8(text: str, byte_limit: int) -> list[str]:
if byte_limit <= 0:
return [text]
if not text:
return [text]
chunks: list[str] = []
remaining = text
while remaining:
encoded = remaining.encode("utf-8")
if len(encoded) <= byte_limit:
chunks.append(remaining)
break
cut = _find_cut_point(encoded, byte_limit)
chunk_bytes = encoded[:cut]
chunk = chunk_bytes.decode("utf-8", errors="strict")
chunks.append(chunk)
remaining = remaining[len(chunk) :]
return chunks
def _utf8_char_len(byte: int) -> int:
if byte & 0x80 == 0:
return 1
if byte & 0xE0 == 0xC0:
return 2
if byte & 0xF0 == 0xE0:
return 3
if byte & 0xF8 == 0xF0:
return 4
return 1
def _find_cut_point(encoded: bytes, byte_limit: int) -> int:
cut = byte_limit
while cut > 0 and (encoded[cut - 1] & 0xC0) == 0x80:
cut -= 1
if cut == 0:
cut = max(1, byte_limit)
if cut > 0 and encoded[cut - 1] & 0x80:
char_len = _utf8_char_len(encoded[cut - 1])
if cut - 1 + char_len > byte_limit:
cut -= 1
return max(1, cut)
def calc_effective_limit(
target: str,
nick: str = "",
username: str = "",
server: str = "",
) -> int:
prefix = f":{nick}!{username}@{server} PRIVMSG {target} :"
overhead = len(prefix.encode("utf-8")) + 2
return max(64, 510 - overhead)
def split_markdown(text: str, byte_limit: int) -> list[str]:
if byte_limit <= 0:
return [text]
if not text:
return [text]
chunks: list[str] = []
paragraphs = _split_markdown_paragraphs(text)
for para in paragraphs:
if len(para.encode("utf-8")) <= byte_limit:
chunks.append(para)
else:
chunks.extend(_split_paragraph_on_boundaries(para, byte_limit))
return chunks
def _split_markdown_paragraphs(text: str) -> list[str]:
raw_paras = text.split("\n\n")
result: list[str] = []
for para in raw_paras:
stripped = para.strip()
if stripped:
result.append(stripped)
return result or [text]
def _split_paragraph_on_boundaries(text: str, byte_limit: int) -> list[str]:
chunks: list[str] = []
words = text.split(" ")
current = ""
for word in words:
candidate = f"{current} {word}" if current else word
if len(candidate.encode("utf-8")) <= byte_limit:
current = candidate
else:
if current:
chunks.append(current)
if len(word.encode("utf-8")) > byte_limit:
chunks.extend(split_utf8(word, byte_limit))
current = ""
else:
current = word
if current:
chunks.append(current)
return chunks
def split_irc_text(text: str, max_chars: int = 350) -> list[str]:
if max_chars <= 0 or not text:
return [text]
byte_limit = min(max_chars * 4, 1600)
return split_utf8(text, byte_limit)