同声自相应,同心自相知。—— 傅玄《何当行》
Welcome to Project Podris. This documentation will guide you through obtaining access to PSC and establishing your first connection.
欢迎加入破灾实控。本文档将指导你获取 PSC 的访问权限,并快速建立首个连接。
INFO 信息
PSC stands for Podris Service Center, the server that distributes intelligence to Project Podris clients.
PSC 即 Podris Service Center,是破灾实控向客户端分发情报的服务器。
Before proceeding, ensure you meet the following requirements to access the Project Podris API
在此之前,你需要满足以下条件才能访问 PSC 的接口进行开发:
- Basic programming proficiency
具备基础的编程能力 - A valid Tencent QQ account
持有一个常用的腾讯 QQ 账号 - Client located within mainland China
客户端位于中国大陆
Project Podris is provided as a public welfare service. To prevent abuse, we require token authentication tied to a Tencent QQ account.
破灾实控是一项公益服务。为防止服务被滥用,我们采用令牌认证机制,且令牌须与您的腾讯 QQ 账号绑定。
Join the group chat (Group ID: 172185748) to review the token usage policy and obtain your token.
请加入群聊(群号:172185748),了解令牌使用规则后获取你的令牌。
ATTENTION 注意
Keep your token secure and do not share it with others. Each token is for individual use only. If you are releasing software that connects to PSC publicly, direct your users to obtain their own tokens rather than embedding one in your application.
请妥善保管你的令牌,勿与他人分享。每个令牌仅限个人使用。若你开发的软件需要公开发布并连接 PSC,应引导用户自行获取令牌,而非将令牌直接内嵌于应用中。
Here is a classic Python 3 PSC client example. It implements core features including token-based authentication, real-time parsing and output of intelligence payloads, and exponential backoff for connection error handling.
这是一个基于 Python 3 的经典 PSC 客户端示例。它实现了令牌认证连接、实时解析并输出情报字典等核心功能,同时采用指数退避策略处理连接错误。
First, install the websockets module in your Python environment.
首先您需要在您的 Python 环境中安装 websockets 模块
Next, create a new Python script and paste the code below:
然后将以下内容复制到一个新的Python脚本文件中:
import asyncio
import websockets
import json
import base64
import brotli
import time
SERVER = "<PSC_ADDRESS>"
TOKEN = "<PSC_TOKEN>"
async def main():
retry_count = 0 # Retry count
while True:
try:
async with websockets.connect(f"ws://{SERVER}/stable?token={TOKEN}") as ws:
while True:
raw = await ws.recv()
decoded = base64.b64decode(raw) # Decode
decompressed = brotli.decompress(decoded) # Decompress
data = json.loads(decompressed)
if "ver" in data: # Handshake
latency = (time.time_ns() // 1_000_000) - data["time"]
print(f"[HANDSHAKE] Latency: {latency} ms | Server Version: {data['ver']}")
retry_count = 0 # Reset retry count on successful handshake
continue
print(f"Received: {data}")
except Exception as e:
print(f"ERROR: {e}")
# Handle connection errors using exponential backoff
retry_count = min(retry_count + 1, 8) # Maximum retry limit
sleep_time = 2 ** retry_count
print(f"Retry count: [{retry_count}], sleeping {sleep_time} s")
await asyncio.sleep(sleep_time)
if __name__ == "__main__":
asyncio.run(main())
ATTENTION 注意
You have to replace <PSC_ADDRESS> in the script with your PSC server address (domain and port, e.g., example.com:1145), and <PSC_TOKEN> with your token.
您还需要将脚本中的 <PSC_ADDRESS> 替换为 PSC 服务器地址(包含域名和端口,例如 example.com:1145),将 <PSC_TOKEN> 替换为你获取的令牌。
Save and run the script. If everything goes smoothly, you should see output similar to below:
保存并运行脚本。如果一切顺利,你将看到类似以下的输出:
[HANDSHAKE] Latency: 114ms | Server Version: 5.14
当 PSC 分发给您新情报时,程序应该会继续输出:
When PSC distributes new intelligence to you, the program should continue to output:
Received: {'msg_id': 0, 'event_id': 0, 'event_type': 'EQR', 'event_source': '中国地震台网[正式测定]', 'time': '2025-02-12 01:10:23', 'region': '西藏那曲市双湖县', 'location': [33.81, 89.15], 'magnitude': 3.9, 'mag_type': 'Ms', 'intensity': 6.0, 'int_type': 'CSIS', 'depth': 10, 'area_intensity': [], 'detail_link': 'https://www.ceic.ac.cn/'}
*以上输出均是示例,您实际得到的输出会有差异 The above outputs are examples, and the actual outputs you receive may vary.
In the previous example, your client passively waited for server pushes. But PSC also supports active data interfaces — you can send plain-text commands to request specific data at any time.
在上个示例中,你的客户端只是被动地等待服务器推送数据。但 PSC 也支持主动数据接口——你可以随时向服务器发送纯文本指令,请求特定的数据。
The following Python example demonstrates how to actively request the latest three earthquake records.
接下来的 Python 实例展示了如何主动请求最近的三条地震记录。
import asyncio
import websockets
import json
import base64
import brotli
import time
SERVER = "<PSC_ADDRESS>"
TOKEN = "<PSC_TOKEN>"
async def main():
retry_count = 0 # Retry count
while True:
try:
async with websockets.connect(f"ws://{SERVER}/stable?token={TOKEN}") as ws:
# Wait for handshake
raw = await ws.recv()
decoded = base64.b64decode(raw) # Decode
decompressed = brotli.decompress(decoded) # Decompress
data = json.loads(decompressed)
if "ver" in data: # Handshake
latency = (time.time_ns() // 1_000_000) - data["time"]
print(f"[HANDSHAKE] Latency: {latency} ms | Server Version: {data['ver']}")
retry_count = 0 # Reset retry count on successful handshake
# Request the latest 3 earthquake records
await ws.send("get_eqlist 3")
# Receive response
raw = await ws.recv()
decoded = base64.b64decode(raw) # Decode
decompressed = brotli.decompress(decoded) # Decompress
history = json.loads(decompressed)
print(f"Received {len(history)} earthquake record(s):")
for item in history:
evt = item.get("event_type", "N/A")
region = item.get("region", "N/A")
mag = item.get("magnitude", "N/A")
print(f" - [{evt}] {region} M{mag}")
# Exit after output
break
except Exception as e:
print(f"ERROR: {e}")
# Handle connection errors using exponential backoff
retry_count = min(retry_count + 1, 8) # Maximum retry limit
sleep_time = 2 ** retry_count
print(f"Retry count: [{retry_count}], sleeping {sleep_time} s")
await asyncio.sleep(sleep_time)
if __name__ == "__main__":
asyncio.run(main())
Save and run the script. If everything goes smoothly, you should see output similar to below:
保存并运行脚本。如果一切顺利,你将看到类似以下的输出:
[HANDSHAKE] Latency: 114 ms | Server Version: 5.14
Received 3 earthquake record(s):
- [EQR] Location1 M1.1
- [EEW] Location2 M4.5
- [CMT] Location3 M1.4
*以上输出均是示例,您实际得到的输出会有差异 The above outputs are examples, and the actual outputs you receive may vary.
Keep practicing by modifying the example parameters to get different outputs. Once done, please read the next document.
你可以继续练习,尝试修改示例中的参数以获得不同的输出。完成后,请阅读下一篇文档。