259 lines
7.8 KiB
PHP
259 lines
7.8 KiB
PHP
<?php
|
||
// +----------------------------------------------------------------------
|
||
// | YwxApp [ WE CAN DO IT JUST THINK ]
|
||
// +----------------------------------------------------------------------
|
||
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
|
||
// +----------------------------------------------------------------------
|
||
// | Author: ywxapp<admin@ywxapp.cn>
|
||
// +----------------------------------------------------------------------
|
||
declare (strict_types = 1);
|
||
|
||
namespace addon\wxchat\worker;
|
||
|
||
/**
|
||
* 消息实体类
|
||
*/
|
||
class Message implements \JsonSerializable
|
||
{
|
||
private array $fields = ['header', 'payload'];
|
||
private Header $header; // 消息扩展信息
|
||
private Payload $payload; // 消息扩展信息
|
||
|
||
|
||
public function __construct()
|
||
{
|
||
$this->header = new Header();
|
||
$this->payload = new Payload();
|
||
}
|
||
|
||
|
||
public function __set($name, $value)
|
||
{
|
||
$this->$name = $value;
|
||
}
|
||
|
||
|
||
public function __get($name)
|
||
{
|
||
if (isset($this->$name)) {
|
||
return $this->$name;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
|
||
public function jsonSerialize(): array
|
||
{
|
||
$data = [];
|
||
foreach ($this->fields as $key) {
|
||
if (isset($this->$key) && $this->$key !== null) {
|
||
$data[$key] = $this->$key;
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
// 反序列化:JSON → Message
|
||
|
||
public static function fromJson(string $json): self
|
||
{
|
||
$data = json_decode($json, true);
|
||
if (! is_array($data)) {
|
||
throw new \InvalidArgumentException('Invalid JSON structure');
|
||
}
|
||
return self::fromArray($data);
|
||
}
|
||
|
||
// 反序列化:数组 → Message
|
||
|
||
public static function fromArray(array $data): self
|
||
{
|
||
$message = new self();
|
||
foreach ($message->fields as $key) {
|
||
if (! isset($data[$key]) || empty($data[$key])) {
|
||
continue;
|
||
}
|
||
if ($key == 'header') {
|
||
$message->header = Header::fromArray($data['header']);
|
||
} else if ($key == 'payload') {
|
||
$message->payload = Payload::fromArray($data['payload']);
|
||
} else {
|
||
$message->$key = $data[$key];
|
||
}
|
||
}
|
||
return $message;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 消息头信息
|
||
*/
|
||
class Header implements \JsonSerializable
|
||
{
|
||
protected array $fields = ['frame', 'id', 'type', 'target', 'seqno', 'timestamp', 'source', 'version', 'token', 'platform', 'device_id', 'network_type'];
|
||
private string $id; // 消息唯一ID(雪花算法生成,必填)
|
||
private string $type = ''; // 消息类型(必填)
|
||
private string $target = 'system'; // 目标会话类型(single/group/room/system,选填)
|
||
private int $seqno = 0; // 消息序列号(同一会话内递增,或全局唯一)
|
||
private int $timestamp; // 消息生成时间(Unix时间戳,毫秒级)
|
||
private string $source = 'server'; // 消息来源(user_id或system,选填)
|
||
private string $version = '1.0.0'; // 协议版本(默认1.0.0,选填)
|
||
private string $token; // 认证Token(选填,连接控制帧可选)
|
||
private string $platform; // 平台类型
|
||
private string $device_id; // 设备ID
|
||
private string $network_type; // 网络类型
|
||
|
||
|
||
public function __construct()
|
||
{
|
||
$this->id = 'msg_' . substr(md5(uniqid((string) mt_rand(), true)), 0, 16);
|
||
$this->timestamp = time() * 1000; // 毫秒级时间戳
|
||
}
|
||
|
||
//__set()方法用来设置私有属性
|
||
|
||
public function __set($name, $value)
|
||
{
|
||
$this->$name = $value;
|
||
}
|
||
|
||
//__get()方法用来获取私有属性
|
||
|
||
public function __get($name)
|
||
{
|
||
return $this->$name;
|
||
}
|
||
|
||
// ✅ 严格实现接口方法
|
||
|
||
public function jsonSerialize(): array
|
||
{
|
||
$data = [];
|
||
foreach ($this->fields as $key) {
|
||
if (isset($this->$key) && $this->$key !== null) {
|
||
$data[$key] = $this->$key;
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
|
||
public function toArray(): array
|
||
{
|
||
// 仅输出非 null 值(符合“可选字段”语义)
|
||
$data = [];
|
||
foreach ($this->fields as $key) {
|
||
if (isset($this->$key) && $value !== null) {
|
||
$data[$key] = $value;
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
// 反序列化:JSON → Message
|
||
|
||
public static function fromJson(string $json): self
|
||
{
|
||
$data = json_decode($json, true);
|
||
if (! is_array($data)) {
|
||
throw new \InvalidArgumentException('Invalid JSON structure');
|
||
}
|
||
return self::fromArray($data);
|
||
}
|
||
|
||
|
||
public static function fromArray(array $data): self
|
||
{
|
||
$header = new self();
|
||
foreach ($header->fields as $key) {
|
||
if (isset($data[$key]) && ! empty($data[$key])) {
|
||
$header->$key = $data[$key];
|
||
}
|
||
}
|
||
return $header;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 消息扩展信息
|
||
*/
|
||
class Payload implements \JsonSerializable
|
||
{
|
||
|
||
private array $fields = ['uid', 'nickname', 'avatar', 'session_id', 'receiver', 'content', 'type', 'status', 'msg_id', 'at_user', 'ext'];
|
||
private int $uid = 0; // 用户ID(发送者)
|
||
private string $nickname; // 昵称(可选,用于显示)
|
||
private string $avatar; // 头像URL(可选,用于显示)
|
||
private string $session_id; // 会话ID(单聊为对方UID,群聊为group_id,系统消息可选)
|
||
private int $receiver; // 接收用户UID(单聊必填,群聊可选)
|
||
private mixed $content; // 消息内容(文本直接字符串,其他类型可为URL或结构化数据)
|
||
private string $type; // 消息类型(text/image/voice/video/file/system/notification/typing/read/revoke)
|
||
private string $status = 'delivered'; // 消息状态(sending/sent/delivered/read/failed)
|
||
private string $msg_id; // 消息ID(可选,服务端生成或客户端指定)
|
||
private array $at_user; // @了哪些人(可选,群聊中使用)
|
||
private mixed $ext; // 扩展字段(可选,根据业务需求定义)
|
||
|
||
//__set()方法用来设置私有属性
|
||
|
||
public function __set($name, $value)
|
||
{
|
||
$this->$name = $value;
|
||
}
|
||
|
||
//__get()方法用来获取私有属性
|
||
|
||
public function __get($name)
|
||
{
|
||
return $this->$name;
|
||
}
|
||
|
||
|
||
public function jsonSerialize(): array
|
||
{
|
||
$data = [];
|
||
foreach ($this->fields as $key) {
|
||
if (isset($this->$key) && $this->$key !== null) {
|
||
$data[$key] = $this->$key;
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
|
||
public function toArray(): array
|
||
{
|
||
// 仅输出非 null 值(符合“可选字段”语义)
|
||
$data = [];
|
||
foreach ($this->fields as $key) {
|
||
$value = $this->$key ?? null;
|
||
if (isset($this->$key) && $value !== null) {
|
||
$data[$key] = $value;
|
||
}
|
||
}
|
||
return $data;
|
||
}
|
||
|
||
|
||
public static function fromJson(string $json): self
|
||
{
|
||
$data = json_decode($json, true);
|
||
if (! is_array($data)) {
|
||
throw new \InvalidArgumentException('Invalid JSON structure');
|
||
}
|
||
return self::fromArray($data);
|
||
}
|
||
|
||
|
||
public static function fromArray(array $data): self
|
||
{
|
||
$payload = new self();
|
||
foreach ($payload->fields as $key) {
|
||
if (isset($data[$key]) && ! empty($data[$key])) {
|
||
$payload->$key = $data[$key];
|
||
}
|
||
}
|
||
return $payload;
|
||
}
|
||
// 其他属性的 getter/setter 按相同模式补充...
|
||
}
|