Skip to content
69 changes: 43 additions & 26 deletions LTS.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#!/usr/bin/env python3

# TouchFish LTS Client/Server Unified Program (Final Release, Version 4)




# TouchFish LTS Client/Server Unified Program (Security Updates, Version 4)



Expand All @@ -9,7 +13,7 @@
"""
# TouchFish 协议文档

本协议文档版本:v2.4.0
本协议文档版本:v2.6.0

本协议分为三个部分:`Gate`,`Chat`,`Misc`。

Expand All @@ -19,6 +23,10 @@

# 协议更新日志

- Protocol v2.6.0 (TouchFish v4.9.0)
- 恢复 v2.3.0 的字段更改
- Protocol v2.5.0 (TouchFish v4.8.0)
- 撤销 v2.3.0 的字段更改
- Protocol v2.4.0 (TouchFish v4.7.0)
- 在 MISC.START 添加 stamp 字段
- Protocol v2.3.0 (TouchFish v4.6.0)
Expand Down Expand Up @@ -111,7 +119,7 @@

- `type`: `"GATE.CLIENT_REQUEST.LOG"`
- `time`: 同上。
- `ip`: 客户端 IP 地址与端口。
- `ip`: 客户端 IP 地址与端口。
- `username`: 用户名。
- `uid`: 用户 ID。

Expand Down Expand Up @@ -142,7 +150,7 @@

当用户状态变更时,服务端进行广播。

- `type`: `"GATE.STATUS_CHANGE.ANNOUNCE"`
- `type`: `"GATE.STATUS_CHANGE.ANNOUNCE"`
- `status`: 新状态。
- `uid`: 被变更状态的用户 ID。

Expand All @@ -152,9 +160,9 @@

服务端将用户状态变更事件写入日志。

- `type`: 固定为 `"GATE.STATUS_CHANGE.LOG"`。
- `time`: 同上。
- `status`: 新状态。(`Pending` 状态和 `Root` 状态不会出现)
- `type`: 固定为 `"GATE.STATUS_CHANGE.LOG"`。
- `time`: 同上。
- `status`: 新状态。(`Pending` 状态和 `Root` 状态不会出现)
- `uid`: 被操作用户的用户 ID。
- `operator`: 操作者的用户 ID。

Expand All @@ -172,9 +180,9 @@

- `type`: `"CHAT.SEND"`
- `filename`: 文件名。若发送的是普通文本消息,则为空字符串 `""`;若发送文件,则为原始文件名。(下同)
- `content`: 若为消息,则为原始文本内容;若为文件,则为文件内容的 Base64 编码字符串。(下同)
- `content`: 若为消息,则为原始文本内容;若为文件,则为文件内容的 Base64 编码字符串。(下同)
- `to`: 目标接收者,可能取值包括:(下同)
- `-2`:广播给所有在线用户(相较于普通发送有特殊提示);
- `-2`:广播给所有在线用户(相较于普通发送有特殊提示);
- `-1`:发送给所有在线用户;
- 非负整数:私聊给拥有相应用户 ID 的用户。

Expand All @@ -184,7 +192,7 @@

服务端将消息转发给目标客户端。

- `type`: `"CHAT.RECEIVE"`
- `type`: `"CHAT.RECEIVE"`
- `from`: 发送者的用户 ID。(下同)
- `order`: 消息编号,可能取值包括:(下同)
- 正整数:普通文本消息;
Expand All @@ -202,7 +210,7 @@
- `type`: `"CHAT.LOG"`
- `time`: 同上。
- `from`: 同上。
- `order`: 同上。
- `order`: 同上。
- `filename`: 同上。
- `content`: 若为消息,则为原始文本内容;若为文件,则为空字符串 `""`。(为了防止日志文件过大,具体的文件内容会单独存储)
- `to`: 同上。
Expand All @@ -215,14 +223,14 @@

## 3.1 Start

`{ type: "MISC.START", time: time, stamp: number, server_version: string, config: JSON }`
`{ type: "MISC.START", time: time, stamp: number, version: string, config: JSON }`

程序将启动时的启动参数写入日志。

- `type`: `"MISC.START"`
- `time`: 同上。
- `time`: 同上。
- `stamp`: 用于指定文件保存路径,取启动时的 UNIX 时间戳乘 `10 ** 6` 后向下取整。
- `server_version`: 字符串,表示服务端程序版本。(下同)
- `version`: 字符串,表示服务端程序版本。(下同)
- `config`: JSON 对象,表示启动参数。(具体格式详见代码,下同)

## 3.2 Data
Expand All @@ -237,7 +245,7 @@
- `config`: 同上。
- `users`: 用户列表,每个元素为:
- `username`: 用户名;
- `status`: 同上。
- `status`: 同上。
- `chat_history`: 历史聊天记录,每条记录包含:(不包含私聊记录和文件发送记录)
- `time`: 同上;
- `order`:同上;
Expand Down Expand Up @@ -324,7 +332,7 @@
服务端将配置修改事件写入日志。

- `type`: `"MISC.CONFIG.LOG"`
- `time`: 同上。
- `time`: 同上。
- `key`: 同上。
- `value`: 同上。
- `operator`: 执行修改操作的用户 ID。
Expand Down Expand Up @@ -354,7 +362,7 @@
import time

# 程序版本
VERSION = "v4.7.0"
VERSION = "v4.9.0"

# 用于客户端解析协议 1.2
RESULTS = \
Expand Down Expand Up @@ -421,7 +429,7 @@
# 需要指出的是,第五部分中会给 username 字段
# 的默认值后面加上一个随机六位数作为后缀,
# 形成形如 "user123456" 的用户名
DEFAULT_CLIENT_CONFIG = {"side": "Client", "ip": "touchfish.xin", "port": 7001, "username": "user"}
DEFAULT_CLIENT_CONFIG = {"side": "Client", "ip": "touchfish.xin", "port": 11451, "username": "user"}

# 默认服务端配置(side 和 general.* 必须在启动时指定):
"""
Expand Down Expand Up @@ -464,7 +472,7 @@
# 中指定的服务端用户名和所发送的文件的内容;
# message.max_length 参数以「字符 (Unicode 码点) 个数」为准,
# 例如「你好」算作 2 个字符;
# message.max_length 参数以「字节个数」为准,
# file.max_size 参数以「字节个数」为准,
# 例如 UTF-8 格式的文本「你好」算作 6 个字节
CONFIG_TYPE_CHECK_TABLE = \
{
Expand Down Expand Up @@ -516,12 +524,12 @@
# 缩写表
ABBREVIATION_TABLE = \
{
"D": "dashboard", "F": "distribute", "Q": "evaluate", "E": "exit", "L": "flood",
"D": "dashboard", "F": "distribute", "Q": "evaluate", "E": "exit", "L": "flood",
"H": "help", "S": "send", "J": "shell", "T": "transfer", "P": "whisper",
"I+": "ban ip add", "I-": "ban ip remove", "W+": "ban words add", "W-": "ban words remove",
"B": "broadcast", "C": "config", "G+": "doorman accept", "G-": "doorman reject", "K": "kick",
"A+": "admin add", "A-": "admin remove", "V": "save",
"d": "dashboard", "f": "distribute", "q": "evaluate", "e": "exit", "l": "flood",
"d": "dashboard", "f": "distribute", "q": "evaluate", "e": "exit", "l": "flood",
"h": "help", "s": "send", "j": "shell", "t": "transfer", "p": "whisper",
"i+": "ban ip add", "i-": "ban ip remove", "w+": "ban words add", "w-": "ban words remove",
"b": "broadcast", "c": "config", "g+": "doorman accept", "g-": "doorman reject", "k": "kick",
Expand Down Expand Up @@ -1001,7 +1009,7 @@ def read():
global buffer
while True:
try:
my_socket.setblocking(False)
my_socket.setblocking(False) # 再次显式设置为非阻塞模式,避免不必要的问题
chunk = my_socket.recv(131072).decode("utf-8")
if not chunk:
break
Expand Down Expand Up @@ -1031,7 +1039,7 @@ def get_message():
partial_message = {key: value for key, value in message.items()}
partial_message["content"] = ""
log_queue.put(json.dumps(partial_message))
else:
else:
# filename 字段为空(或者 filename 字段根本不存在),表明不是文件
impossible_value = message["impossible_key"] # 故意引发 KeyError
except KeyError:
Expand Down Expand Up @@ -1316,7 +1324,7 @@ def do_config(arg, verbose=True, by=-1):
except:
printc(verbose, "指令格式不正确,请重试。")
return

printc(verbose, "操作成功。")

def do_ban(arg, verbose=True, by=-1):
Expand Down Expand Up @@ -1885,7 +1893,11 @@ def thread_gate():
data = ""
while True:
try:
data += conntmp.recv(131072).decode("utf-8")
conntmp.setblocking(False) # 再次显式设置为非阻塞模式,避免不必要的问题
chunk = conntmp.recv(131072).decode("utf-8")
if not chunk:
raise
data += chunk
except:
break

Expand Down Expand Up @@ -2059,7 +2071,7 @@ def thread_send():
# 先按文件处理
if not message["content"]["filename"]: # filename 字段为空(或者 filename 字段根本不存在),表明不是文件
impossible_value = message["content"]["impossible_key"] # 故意引发 KeyError
with open(message["content"]["filename"], "rb") as f:
with open(message["content"]["content"], "rb") as f:
file_data = f.read() # 读取 do_distribute 或 do_transfer 函数先前写入到磁盘的对应文件
message["content"]["content"] = base64.b64encode(file_data).decode("utf-8") # 将 content 字段覆写为正确值
token = json.dumps(message["content"]) + "\n"
Expand Down Expand Up @@ -2293,6 +2305,11 @@ def main():
os.system("") # 对 Windows 尝试开启 ANSI 转义字符(带颜色文本)支持
clear_screen()

prints("我们即将推出 TouchFish v5,敬请期待!", "magenta")
prints("服务端 Github 仓库:https://github.com/2044-space-elevator/TFV5_server", "magenta")
prints("客户端 Github 仓库:https://github.com/ILoveScratch2/TouchFish-Client", "magenta")
print()

if config_read_result == "OK":
prints("配置文件 config.json 读取成功!", "yellow")
if config_read_result == "Not found":
Expand Down
2 changes: 1 addition & 1 deletion PKGBUILD
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Maintainer: TouchFish Community <johnchiao@outlook.com>
pkgname=touchfish
pkgver=4.7.0
pkgver=4.9.0
pkgrel=1
pkgdesc="FOSS multi-distribution LAN chatting tool"
arch=('any')
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
> [!WARNING]
> **这是 TouchFish v4 版本,自 v4 开始不再向前兼容 v1 - v3。**
>
> **根据规划,此版本(v4.7.0)是 TouchFish v4 的最后一个子版本。TouchFish v5 正在施工,[链接](https://github.com/2044-space-elevator/TFV5_server)。下一版本预计将进入 v5。**
> **根据规划,此版本(v4.9.0)是 TouchFish v4 的最后一个子版本。TouchFish v5 正在施工,[链接](https://github.com/2044-space-elevator/TFV5_server)。下一版本预计将进入 v5。**

> [!IMPORTANT]
> **重要通知:贡献者须知**
Expand Down Expand Up @@ -43,9 +43,9 @@
> (这里的命令只针对 Linux 用户)
>
> 不建议下载预编译的二进制文件,建议通过源代码部署
> `wget https://github.com/2044-space-elevator/TouchFish/releases/download/v4.7.0/LTS.py && python3 LTS.py`
> `wget https://github.com/2044-space-elevator/TouchFish/releases/download/v4.9.0/LTS.py && python3 LTS.py`
>
> (也可以通过 @ILoveScratch2 提供的镜像站,但是截至 2026/2/23 只更新到了 v4.6 版本:`wget https://mirror.ilovescratch.us.ci/api/net/379814722/LTS.py && python3 LTS.py`)
> (也可以通过 @ILoveScratch2 提供的镜像站,但是截至 2026/6/17 只更新到了 v4.7.0 版本:`wget https://mirror.ilovescratch.us.ci/api/net/183301217/LTS.py && python3 LTS.py`)

1. **获取内网 IP 地址**:
- **Windows**: 命令提示符执行 `ipconfig`,查找 "无线局域网适配器 WLAN" 下的 "IPv4 地址"
Expand Down Expand Up @@ -143,7 +143,7 @@ TouchFish 拥有丰富的衍生版本生态系统,满足不同用户需求:

> 标 * 的版本可能需要自行编译、直接运行代码或缺少预编译包。
>
> 标 ^ 的版本可能与 LTS v4.6.0/v4.7.0 存在少量兼容性问题,此时建议使用 LTS v4.3.3
> 标 ^ 的版本与 LTS v4.9.0 存在兼容性问题,建议使用 LTS v4.8.0

---

Expand Down