x
This commit is contained in:
25
pkg/appver/version.go
Normal file
25
pkg/appver/version.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package appver
|
||||
|
||||
type Info struct {
|
||||
FilePath string `json:"file_path"`
|
||||
CompanyName string `json:"company_name"`
|
||||
FileDescription string `json:"file_description"`
|
||||
Version int `json:"version"`
|
||||
FullVersion string `json:"full_version"`
|
||||
LegalCopyright string `json:"legal_copyright"`
|
||||
ProductName string `json:"product_name"`
|
||||
ProductVersion string `json:"product_version"`
|
||||
}
|
||||
|
||||
func New(filePath string) (*Info, error) {
|
||||
i := &Info{
|
||||
FilePath: filePath,
|
||||
}
|
||||
|
||||
err := i.initialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
41
pkg/appver/version_darwin.go
Normal file
41
pkg/appver/version_darwin.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package appver
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"howett.net/plist"
|
||||
)
|
||||
|
||||
const (
|
||||
InfoFile = "Info.plist"
|
||||
)
|
||||
|
||||
type Plist struct {
|
||||
CFBundleShortVersionString string `plist:"CFBundleShortVersionString"`
|
||||
NSHumanReadableCopyright string `plist:"NSHumanReadableCopyright"`
|
||||
}
|
||||
|
||||
func (i *Info) initialize() error {
|
||||
|
||||
parts := strings.Split(i.FilePath, string(filepath.Separator))
|
||||
file := filepath.Join(append(parts[:len(parts)-2], InfoFile)...)
|
||||
b, err := os.ReadFile("/" + file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := Plist{}
|
||||
_, err = plist.Unmarshal(b, &p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.FullVersion = p.CFBundleShortVersionString
|
||||
i.Version, _ = strconv.Atoi(strings.Split(i.FullVersion, ".")[0])
|
||||
i.CompanyName = p.NSHumanReadableCopyright
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
//go:build !windows
|
||||
//go:build !windows && !darwin
|
||||
|
||||
package dllver
|
||||
package appver
|
||||
|
||||
func (i *Info) initialize() error {
|
||||
return nil
|
||||
@@ -1,4 +1,4 @@
|
||||
package dllver
|
||||
package appver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -75,13 +75,13 @@ func (i *Info) initialize() error {
|
||||
}
|
||||
|
||||
// 解析文件版本
|
||||
i.FileVersion = fmt.Sprintf("%d.%d.%d.%d",
|
||||
i.FullVersion = fmt.Sprintf("%d.%d.%d.%d",
|
||||
(fixedFileInfo.FileVersionMS>>16)&0xffff,
|
||||
(fixedFileInfo.FileVersionMS>>0)&0xffff,
|
||||
(fixedFileInfo.FileVersionLS>>16)&0xffff,
|
||||
(fixedFileInfo.FileVersionLS>>0)&0xffff,
|
||||
)
|
||||
i.FileMajorVersion = int((fixedFileInfo.FileVersionMS >> 16) & 0xffff)
|
||||
i.Version = int((fixedFileInfo.FileVersionMS >> 16) & 0xffff)
|
||||
|
||||
i.ProductVersion = fmt.Sprintf("%d.%d.%d.%d",
|
||||
(fixedFileInfo.ProductVersionMS>>16)&0xffff,
|
||||
@@ -111,7 +111,7 @@ func (i *Info) initialize() error {
|
||||
stringInfos := map[string]*string{
|
||||
"CompanyName": &i.CompanyName,
|
||||
"FileDescription": &i.FileDescription,
|
||||
"FileVersion": &i.FileVersion,
|
||||
"FileVersion": &i.FullVersion,
|
||||
"LegalCopyright": &i.LegalCopyright,
|
||||
"ProductName": &i.ProductName,
|
||||
"ProductVersion": &i.ProductVersion,
|
||||
@@ -1,25 +0,0 @@
|
||||
package dllver
|
||||
|
||||
type Info struct {
|
||||
FilePath string `json:"file_path"`
|
||||
CompanyName string `json:"company_name"`
|
||||
FileDescription string `json:"file_description"`
|
||||
FileVersion string `json:"file_version"`
|
||||
FileMajorVersion int `json:"file_major_version"`
|
||||
LegalCopyright string `json:"legal_copyright"`
|
||||
ProductName string `json:"product_name"`
|
||||
ProductVersion string `json:"product_version"`
|
||||
}
|
||||
|
||||
func New(filePath string) (*Info, error) {
|
||||
i := &Info{
|
||||
FilePath: filePath,
|
||||
}
|
||||
|
||||
err := i.initialize()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return i, nil
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/sjzar/chatlog/pkg/model/wxproto"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type ChatRoom struct {
|
||||
Name string `json:"name"`
|
||||
Owner string `json:"owner"`
|
||||
Users []ChatRoomUser `json:"users"`
|
||||
|
||||
// Extra From Contact
|
||||
Remark string `json:"remark"`
|
||||
NickName string `json:"nickName"`
|
||||
|
||||
User2DisplayName map[string]string `json:"-"`
|
||||
}
|
||||
|
||||
type ChatRoomUser struct {
|
||||
UserName string `json:"userName"`
|
||||
DisplayName string `json:"displayName"`
|
||||
}
|
||||
|
||||
// CREATE TABLE ChatRoom(
|
||||
// ChatRoomName TEXT PRIMARY KEY,
|
||||
// UserNameList TEXT,
|
||||
// DisplayNameList TEXT,
|
||||
// ChatRoomFlag int Default 0,
|
||||
// Owner INTEGER DEFAULT 0,
|
||||
// IsShowName INTEGER DEFAULT 0,
|
||||
// SelfDisplayName TEXT,
|
||||
// Reserved1 INTEGER DEFAULT 0,
|
||||
// Reserved2 TEXT,
|
||||
// Reserved3 INTEGER DEFAULT 0,
|
||||
// Reserved4 TEXT,
|
||||
// Reserved5 INTEGER DEFAULT 0,
|
||||
// Reserved6 TEXT,
|
||||
// RoomData BLOB,
|
||||
// Reserved7 INTEGER DEFAULT 0,
|
||||
// Reserved8 TEXT
|
||||
// )
|
||||
type ChatRoomV3 struct {
|
||||
ChatRoomName string `json:"ChatRoomName"`
|
||||
Reserved2 string `json:"Reserved2"` // Creator
|
||||
RoomData []byte `json:"RoomData"`
|
||||
|
||||
// // 非关键信息,暂时忽略
|
||||
// UserNameList string `json:"UserNameList"`
|
||||
// DisplayNameList string `json:"DisplayNameList"`
|
||||
// ChatRoomFlag int `json:"ChatRoomFlag"`
|
||||
// Owner int `json:"Owner"`
|
||||
// IsShowName int `json:"IsShowName"`
|
||||
// SelfDisplayName string `json:"SelfDisplayName"`
|
||||
// Reserved1 int `json:"Reserved1"`
|
||||
// Reserved3 int `json:"Reserved3"`
|
||||
// Reserved4 string `json:"Reserved4"`
|
||||
// Reserved5 int `json:"Reserved5"`
|
||||
// Reserved6 string `json:"Reserved6"`
|
||||
// Reserved7 int `json:"Reserved7"`
|
||||
// Reserved8 string `json:"Reserved8"`
|
||||
}
|
||||
|
||||
func (c *ChatRoomV3) Wrap() *ChatRoom {
|
||||
|
||||
var users []ChatRoomUser
|
||||
if len(c.RoomData) != 0 {
|
||||
users = ParseRoomData(c.RoomData)
|
||||
}
|
||||
|
||||
user2DisplayName := make(map[string]string, len(users))
|
||||
for _, user := range users {
|
||||
if user.DisplayName != "" {
|
||||
user2DisplayName[user.UserName] = user.DisplayName
|
||||
}
|
||||
}
|
||||
|
||||
return &ChatRoom{
|
||||
Name: c.ChatRoomName,
|
||||
Owner: c.Reserved2,
|
||||
Users: users,
|
||||
User2DisplayName: user2DisplayName,
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE TABLE chat_room(
|
||||
// id INTEGER PRIMARY KEY,
|
||||
// username TEXT,
|
||||
// owner TEXT,
|
||||
// ext_buffer BLOB
|
||||
// )
|
||||
type ChatRoomV4 struct {
|
||||
ID int `json:"id"`
|
||||
UserName string `json:"username"`
|
||||
Owner string `json:"owner"`
|
||||
ExtBuffer []byte `json:"ext_buffer"`
|
||||
}
|
||||
|
||||
func (c *ChatRoomV4) Wrap() *ChatRoom {
|
||||
|
||||
var users []ChatRoomUser
|
||||
if len(c.ExtBuffer) != 0 {
|
||||
users = ParseRoomData(c.ExtBuffer)
|
||||
}
|
||||
|
||||
return &ChatRoom{
|
||||
Name: c.UserName,
|
||||
Owner: c.Owner,
|
||||
Users: users,
|
||||
}
|
||||
}
|
||||
|
||||
func ParseRoomData(b []byte) (users []ChatRoomUser) {
|
||||
var pbMsg wxproto.RoomData
|
||||
if err := proto.Unmarshal(b, &pbMsg); err != nil {
|
||||
return
|
||||
}
|
||||
if pbMsg.Users == nil {
|
||||
return
|
||||
}
|
||||
|
||||
users = make([]ChatRoomUser, 0, len(pbMsg.Users))
|
||||
for _, user := range pbMsg.Users {
|
||||
u := ChatRoomUser{UserName: user.UserName}
|
||||
if user.DisplayName != nil {
|
||||
u.DisplayName = *user.DisplayName
|
||||
}
|
||||
users = append(users, u)
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
func (c *ChatRoom) DisplayName() string {
|
||||
switch {
|
||||
case c.Remark != "":
|
||||
return c.Remark
|
||||
case c.NickName != "":
|
||||
return c.NickName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package model
|
||||
|
||||
type Contact struct {
|
||||
UserName string `json:"userName"`
|
||||
Alias string `json:"alias"`
|
||||
Remark string `json:"remark"`
|
||||
NickName string `json:"nickName"`
|
||||
IsFriend bool `json:"isFriend"`
|
||||
}
|
||||
|
||||
// CREATE TABLE Contact(
|
||||
// UserName TEXT PRIMARY KEY ,
|
||||
// Alias TEXT,
|
||||
// EncryptUserName TEXT,
|
||||
// DelFlag INTEGER DEFAULT 0,
|
||||
// Type INTEGER DEFAULT 0,
|
||||
// VerifyFlag INTEGER DEFAULT 0,
|
||||
// Reserved1 INTEGER DEFAULT 0,
|
||||
// Reserved2 INTEGER DEFAULT 0,
|
||||
// Reserved3 TEXT,
|
||||
// Reserved4 TEXT,
|
||||
// Remark TEXT,
|
||||
// NickName TEXT,
|
||||
// LabelIDList TEXT,
|
||||
// DomainList TEXT,
|
||||
// ChatRoomType int,
|
||||
// PYInitial TEXT,
|
||||
// QuanPin TEXT,
|
||||
// RemarkPYInitial TEXT,
|
||||
// RemarkQuanPin TEXT,
|
||||
// BigHeadImgUrl TEXT,
|
||||
// SmallHeadImgUrl TEXT,
|
||||
// HeadImgMd5 TEXT,
|
||||
// ChatRoomNotify INTEGER DEFAULT 0,
|
||||
// Reserved5 INTEGER DEFAULT 0,
|
||||
// Reserved6 TEXT,
|
||||
// Reserved7 TEXT,
|
||||
// ExtraBuf BLOB,
|
||||
// Reserved8 INTEGER DEFAULT 0,
|
||||
// Reserved9 INTEGER DEFAULT 0,
|
||||
// Reserved10 TEXT,
|
||||
// Reserved11 TEXT
|
||||
// )
|
||||
type ContactV3 struct {
|
||||
UserName string `json:"UserName"`
|
||||
Alias string `json:"Alias"`
|
||||
Remark string `json:"Remark"`
|
||||
NickName string `json:"NickName"`
|
||||
Reserved1 int `json:"Reserved1"` // 1 自己好友或自己加入的群聊; 0 群聊成员(非好友)
|
||||
|
||||
// EncryptUserName string `json:"EncryptUserName"`
|
||||
// DelFlag int `json:"DelFlag"`
|
||||
// Type int `json:"Type"`
|
||||
// VerifyFlag int `json:"VerifyFlag"`
|
||||
// Reserved2 int `json:"Reserved2"`
|
||||
// Reserved3 string `json:"Reserved3"`
|
||||
// Reserved4 string `json:"Reserved4"`
|
||||
// LabelIDList string `json:"LabelIDList"`
|
||||
// DomainList string `json:"DomainList"`
|
||||
// ChatRoomType int `json:"ChatRoomType"`
|
||||
// PYInitial string `json:"PYInitial"`
|
||||
// QuanPin string `json:"QuanPin"`
|
||||
// RemarkPYInitial string `json:"RemarkPYInitial"`
|
||||
// RemarkQuanPin string `json:"RemarkQuanPin"`
|
||||
// BigHeadImgUrl string `json:"BigHeadImgUrl"`
|
||||
// SmallHeadImgUrl string `json:"SmallHeadImgUrl"`
|
||||
// HeadImgMd5 string `json:"HeadImgMd5"`
|
||||
// ChatRoomNotify int `json:"ChatRoomNotify"`
|
||||
// Reserved5 int `json:"Reserved5"`
|
||||
// Reserved6 string `json:"Reserved6"`
|
||||
// Reserved7 string `json:"Reserved7"`
|
||||
// ExtraBuf []byte `json:"ExtraBuf"`
|
||||
// Reserved8 int `json:"Reserved8"`
|
||||
// Reserved9 int `json:"Reserved9"`
|
||||
// Reserved10 string `json:"Reserved10"`
|
||||
// Reserved11 string `json:"Reserved11"`
|
||||
}
|
||||
|
||||
func (c *ContactV3) Wrap() *Contact {
|
||||
return &Contact{
|
||||
UserName: c.UserName,
|
||||
Alias: c.Alias,
|
||||
Remark: c.Remark,
|
||||
NickName: c.NickName,
|
||||
IsFriend: c.Reserved1 == 1,
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE TABLE contact(
|
||||
// id INTEGER PRIMARY KEY,
|
||||
// username TEXT,
|
||||
// local_type INTEGER,
|
||||
// alias TEXT,
|
||||
// encrypt_username TEXT,
|
||||
// flag INTEGER,
|
||||
// delete_flag INTEGER,
|
||||
// verify_flag INTEGER,
|
||||
// remark TEXT,
|
||||
// remark_quan_pin TEXT,
|
||||
// remark_pin_yin_initial TEXT,
|
||||
// nick_name TEXT,
|
||||
// pin_yin_initial TEXT,
|
||||
// quan_pin TEXT,
|
||||
// big_head_url TEXT,
|
||||
// small_head_url TEXT,
|
||||
// head_img_md5 TEXT,
|
||||
// chat_room_notify INTEGER,
|
||||
// is_in_chat_room INTEGER,
|
||||
// description TEXT,
|
||||
// extra_buffer BLOB,
|
||||
// chat_room_type INTEGER
|
||||
// )
|
||||
type ContactV4 struct {
|
||||
UserName string `json:"username"`
|
||||
Alias string `json:"alias"`
|
||||
Remark string `json:"remark"`
|
||||
NickName string `json:"nick_name"`
|
||||
LocalType int `json:"local_type"` // 2 群聊; 3 群聊成员(非好友); 5,6 企业微信;
|
||||
|
||||
// ID int `json:"id"`
|
||||
|
||||
// EncryptUserName string `json:"encrypt_username"`
|
||||
// Flag int `json:"flag"`
|
||||
// DeleteFlag int `json:"delete_flag"`
|
||||
// VerifyFlag int `json:"verify_flag"`
|
||||
// RemarkQuanPin string `json:"remark_quan_pin"`
|
||||
// RemarkPinYinInitial string `json:"remark_pin_yin_initial"`
|
||||
// PinYinInitial string `json:"pin_yin_initial"`
|
||||
// QuanPin string `json:"quan_pin"`
|
||||
// BigHeadUrl string `json:"big_head_url"`
|
||||
// SmallHeadUrl string `json:"small_head_url"`
|
||||
// HeadImgMd5 string `json:"head_img_md5"`
|
||||
// ChatRoomNotify int `json:"chat_room_notify"`
|
||||
// IsInChatRoom int `json:"is_in_chat_room"`
|
||||
// Description string `json:"description"`
|
||||
// ExtraBuffer []byte `json:"extra_buffer"`
|
||||
// ChatRoomType int `json:"chat_room_type"`
|
||||
}
|
||||
|
||||
func (c *ContactV4) Wrap() *Contact {
|
||||
return &Contact{
|
||||
UserName: c.UserName,
|
||||
Alias: c.Alias,
|
||||
Remark: c.Remark,
|
||||
NickName: c.NickName,
|
||||
IsFriend: c.LocalType != 3,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Contact) DisplayName() string {
|
||||
switch {
|
||||
case c.Remark != "":
|
||||
return c.Remark
|
||||
case c.NickName != "":
|
||||
return c.NickName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/sjzar/chatlog/pkg/model/wxproto"
|
||||
"github.com/sjzar/chatlog/pkg/util"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
// Source
|
||||
WeChatV3 = "wechatv3"
|
||||
WeChatV4 = "wechatv4"
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Sequence int64 `json:"sequence"` // 消息序号,10位时间戳 + 3位序号
|
||||
CreateTime time.Time `json:"createTime"` // 消息创建时间,10位时间戳
|
||||
TalkerID int `json:"talkerID"` // 聊天对象,Name2ID 表序号,索引值
|
||||
Talker string `json:"talker"` // 聊天对象,微信 ID or 群 ID
|
||||
IsSender int `json:"isSender"` // 是否为发送消息,0 接收消息,1 发送消息
|
||||
Type int `json:"type"` // 消息类型
|
||||
SubType int `json:"subType"` // 消息子类型
|
||||
Content string `json:"content"` // 消息内容,文字聊天内容 或 XML
|
||||
CompressContent []byte `json:"compressContent"` // 非文字聊天内容,如图片、语音、视频等
|
||||
IsChatRoom bool `json:"isChatRoom"` // 是否为群聊消息
|
||||
ChatRoomSender string `json:"chatRoomSender"` // 群聊消息发送人
|
||||
|
||||
// Fill Info
|
||||
// 从联系人等信息中填充
|
||||
DisplayName string `json:"-"` // 显示名称
|
||||
CharRoomName string `json:"-"` // 群聊名称
|
||||
|
||||
Version string `json:"-"` // 消息版本,内部判断
|
||||
}
|
||||
|
||||
// CREATE TABLE MSG (
|
||||
// localId INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
// TalkerId INT DEFAULT 0,
|
||||
// MsgSvrID INT,
|
||||
// Type INT,
|
||||
// SubType INT,
|
||||
// IsSender INT,
|
||||
// CreateTime INT,
|
||||
// Sequence INT DEFAULT 0,
|
||||
// StatusEx INT DEFAULT 0,
|
||||
// FlagEx INT,
|
||||
// Status INT,
|
||||
// MsgServerSeq INT,
|
||||
// MsgSequence INT,
|
||||
// StrTalker TEXT,
|
||||
// StrContent TEXT,
|
||||
// DisplayContent TEXT,
|
||||
// Reserved0 INT DEFAULT 0,
|
||||
// Reserved1 INT DEFAULT 0,
|
||||
// Reserved2 INT DEFAULT 0,
|
||||
// Reserved3 INT DEFAULT 0,
|
||||
// Reserved4 TEXT,
|
||||
// Reserved5 TEXT,
|
||||
// Reserved6 TEXT,
|
||||
// CompressContent BLOB,
|
||||
// BytesExtra BLOB,
|
||||
// BytesTrans BLOB
|
||||
// )
|
||||
type MessageV3 struct {
|
||||
Sequence int64 `json:"Sequence"` // 消息序号,10位时间戳 + 3位序号
|
||||
CreateTime int64 `json:"CreateTime"` // 消息创建时间,10位时间戳
|
||||
TalkerID int `json:"TalkerId"` // 聊天对象,Name2ID 表序号,索引值
|
||||
StrTalker string `json:"StrTalker"` // 聊天对象,微信 ID or 群 ID
|
||||
IsSender int `json:"IsSender"` // 是否为发送消息,0 接收消息,1 发送消息
|
||||
Type int `json:"Type"` // 消息类型
|
||||
SubType int `json:"SubType"` // 消息子类型
|
||||
StrContent string `json:"StrContent"` // 消息内容,文字聊天内容 或 XML
|
||||
CompressContent []byte `json:"CompressContent"` // 非文字聊天内容,如图片、语音、视频等
|
||||
BytesExtra []byte `json:"BytesExtra"` // protobuf 额外数据,记录群聊发送人等信息
|
||||
|
||||
// 非关键信息,后续有需要再加入
|
||||
// LocalID int64 `json:"localId"`
|
||||
// MsgSvrID int64 `json:"MsgSvrID"`
|
||||
// StatusEx int `json:"StatusEx"`
|
||||
// FlagEx int `json:"FlagEx"`
|
||||
// Status int `json:"Status"`
|
||||
// MsgServerSeq int64 `json:"MsgServerSeq"`
|
||||
// MsgSequence int64 `json:"MsgSequence"`
|
||||
// DisplayContent string `json:"DisplayContent"`
|
||||
// Reserved0 int `json:"Reserved0"`
|
||||
// Reserved1 int `json:"Reserved1"`
|
||||
// Reserved2 int `json:"Reserved2"`
|
||||
// Reserved3 int `json:"Reserved3"`
|
||||
// Reserved4 string `json:"Reserved4"`
|
||||
// Reserved5 string `json:"Reserved5"`
|
||||
// Reserved6 string `json:"Reserved6"`
|
||||
// BytesTrans []byte `json:"BytesTrans"`
|
||||
}
|
||||
|
||||
func (m *MessageV3) Wrap() *Message {
|
||||
|
||||
isChatRoom := strings.HasSuffix(m.StrTalker, "@chatroom")
|
||||
|
||||
var chatRoomSender string
|
||||
if len(m.BytesExtra) != 0 && isChatRoom {
|
||||
chatRoomSender = ParseBytesExtra(m.BytesExtra)
|
||||
}
|
||||
|
||||
return &Message{
|
||||
Sequence: m.Sequence,
|
||||
CreateTime: time.Unix(m.CreateTime, 0),
|
||||
TalkerID: m.TalkerID,
|
||||
Talker: m.StrTalker,
|
||||
IsSender: m.IsSender,
|
||||
Type: m.Type,
|
||||
SubType: m.SubType,
|
||||
Content: m.StrContent,
|
||||
CompressContent: m.CompressContent,
|
||||
IsChatRoom: isChatRoom,
|
||||
ChatRoomSender: chatRoomSender,
|
||||
Version: WeChatV3,
|
||||
}
|
||||
}
|
||||
|
||||
// CREATE TABLE Msg_xxxxxxxxxxxx(
|
||||
// local_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
// server_id INTEGER,
|
||||
// local_type INTEGER,
|
||||
// sort_seq INTEGER,
|
||||
// real_sender_id INTEGER,
|
||||
// create_time INTEGER,
|
||||
// status INTEGER,
|
||||
// upload_status INTEGER,
|
||||
// download_status INTEGER,
|
||||
// server_seq INTEGER,
|
||||
// origin_source INTEGER,
|
||||
// source TEXT,
|
||||
// message_content TEXT,
|
||||
// compress_content TEXT,
|
||||
// packed_info_data BLOB,
|
||||
// WCDB_CT_message_content INTEGER DEFAULT NULL,
|
||||
// WCDB_CT_source INTEGER DEFAULT NULL
|
||||
// )
|
||||
type MessageV4 struct {
|
||||
SortSeq int64 `json:"sort_seq"` // 消息序号,10位时间戳 + 3位序号
|
||||
LocalType int `json:"local_type"` // 消息类型
|
||||
RealSenderID int `json:"real_sender_id"` // 发送人 ID,对应 Name2Id 表序号
|
||||
CreateTime int64 `json:"create_time"` // 消息创建时间,10位时间戳
|
||||
MessageContent []byte `json:"message_content"` // 消息内容,文字聊天内容 或 zstd 压缩内容
|
||||
PackedInfoData []byte `json:"packed_info_data"` // 额外数据,类似 proto,格式与 v3 有差异
|
||||
Status int `json:"status"` // 消息状态,2 是已发送,4 是已接收,可以用于判断 IsSender(猜测)
|
||||
|
||||
// 非关键信息,后续有需要再加入
|
||||
// LocalID int `json:"local_id"`
|
||||
// ServerID int64 `json:"server_id"`
|
||||
|
||||
// UploadStatus int `json:"upload_status"`
|
||||
// DownloadStatus int `json:"download_status"`
|
||||
// ServerSeq int `json:"server_seq"`
|
||||
// OriginSource int `json:"origin_source"`
|
||||
// Source string `json:"source"`
|
||||
// CompressContent string `json:"compress_content"`
|
||||
}
|
||||
|
||||
func (m *MessageV4) Wrap(id2Name map[int]string, isChatRoom bool) *Message {
|
||||
|
||||
_m := &Message{
|
||||
Sequence: m.SortSeq,
|
||||
CreateTime: time.Unix(m.CreateTime, 0),
|
||||
TalkerID: m.RealSenderID, // 依赖 Name2Id 表进行转换为 StrTalker
|
||||
CompressContent: m.PackedInfoData,
|
||||
Type: m.LocalType,
|
||||
Version: WeChatV4,
|
||||
}
|
||||
|
||||
if name, ok := id2Name[m.RealSenderID]; ok {
|
||||
_m.Talker = name
|
||||
}
|
||||
|
||||
if m.Status == 2 {
|
||||
_m.IsSender = 1
|
||||
}
|
||||
|
||||
if util.IsNormalString(m.MessageContent) {
|
||||
_m.Content = string(m.MessageContent)
|
||||
} else {
|
||||
_m.CompressContent = m.MessageContent
|
||||
}
|
||||
|
||||
if isChatRoom {
|
||||
_m.IsChatRoom = true
|
||||
split := strings.Split(_m.Content, "\n")
|
||||
if len(split) > 1 {
|
||||
_m.Content = split[1]
|
||||
_m.ChatRoomSender = strings.TrimSuffix(split[0], ":")
|
||||
}
|
||||
}
|
||||
|
||||
return _m
|
||||
}
|
||||
|
||||
// ParseBytesExtra 解析额外数据
|
||||
// 按需解析
|
||||
func ParseBytesExtra(b []byte) (chatRoomSender string) {
|
||||
var pbMsg wxproto.BytesExtra
|
||||
if err := proto.Unmarshal(b, &pbMsg); err != nil {
|
||||
return
|
||||
}
|
||||
if pbMsg.Items == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range pbMsg.Items {
|
||||
if item.Type == 1 {
|
||||
return item.Value
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Message) PlainText(showChatRoom bool) string {
|
||||
buf := strings.Builder{}
|
||||
|
||||
talker := m.Talker
|
||||
if m.IsSender == 1 {
|
||||
talker = "我"
|
||||
} else if m.IsChatRoom {
|
||||
talker = m.ChatRoomSender
|
||||
}
|
||||
if m.DisplayName != "" {
|
||||
buf.WriteString(m.DisplayName)
|
||||
buf.WriteString("(")
|
||||
buf.WriteString(talker)
|
||||
buf.WriteString(")")
|
||||
} else {
|
||||
buf.WriteString(talker)
|
||||
}
|
||||
buf.WriteString(" ")
|
||||
|
||||
if m.IsChatRoom && showChatRoom {
|
||||
buf.WriteString("[")
|
||||
if m.CharRoomName != "" {
|
||||
buf.WriteString(m.CharRoomName)
|
||||
buf.WriteString("(")
|
||||
buf.WriteString(m.Talker)
|
||||
buf.WriteString(")")
|
||||
} else {
|
||||
buf.WriteString(m.Talker)
|
||||
}
|
||||
buf.WriteString("] ")
|
||||
}
|
||||
|
||||
buf.WriteString(m.CreateTime.Format("2006-01-02 15:04:05"))
|
||||
buf.WriteString("\n")
|
||||
|
||||
switch m.Type {
|
||||
case 1:
|
||||
buf.WriteString(m.Content)
|
||||
case 3:
|
||||
buf.WriteString("[图片]")
|
||||
case 34:
|
||||
buf.WriteString("[语音]")
|
||||
case 43:
|
||||
buf.WriteString("[视频]")
|
||||
case 47:
|
||||
buf.WriteString("[动画表情]")
|
||||
case 49:
|
||||
switch m.SubType {
|
||||
case 6:
|
||||
buf.WriteString("[文件]")
|
||||
case 8:
|
||||
buf.WriteString("[GIF表情]")
|
||||
case 19:
|
||||
buf.WriteString("[合并转发]")
|
||||
case 33, 36:
|
||||
buf.WriteString("[小程序]")
|
||||
case 57:
|
||||
buf.WriteString("[引用]")
|
||||
case 63:
|
||||
buf.WriteString("[视频号]")
|
||||
case 87:
|
||||
buf.WriteString("[群公告]")
|
||||
case 2000:
|
||||
buf.WriteString("[转账]")
|
||||
case 2003:
|
||||
buf.WriteString("[红包封面]")
|
||||
default:
|
||||
buf.WriteString("[分享]")
|
||||
}
|
||||
case 50:
|
||||
buf.WriteString("[语音通话]")
|
||||
case 10000:
|
||||
buf.WriteString("[系统消息]")
|
||||
default:
|
||||
buf.WriteString(fmt.Sprintf("Type: %d Content: %s", m.Type, m.Content))
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
|
||||
return buf.String()
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Session struct {
|
||||
UserName string `json:"userName"`
|
||||
NOrder int `json:"nOrder"`
|
||||
NickName string `json:"nickName"`
|
||||
Content string `json:"content"`
|
||||
NTime time.Time `json:"nTime"`
|
||||
}
|
||||
|
||||
// CREATE TABLE Session(
|
||||
// strUsrName TEXT PRIMARY KEY,
|
||||
// nOrder INT DEFAULT 0,
|
||||
// nUnReadCount INTEGER DEFAULT 0,
|
||||
// parentRef TEXT,
|
||||
// Reserved0 INTEGER DEFAULT 0,
|
||||
// Reserved1 TEXT,
|
||||
// strNickName TEXT,
|
||||
// nStatus INTEGER,
|
||||
// nIsSend INTEGER,
|
||||
// strContent TEXT,
|
||||
// nMsgType INTEGER,
|
||||
// nMsgLocalID INTEGER,
|
||||
// nMsgStatus INTEGER,
|
||||
// nTime INTEGER,
|
||||
// editContent TEXT,
|
||||
// othersAtMe INT,
|
||||
// Reserved2 INTEGER DEFAULT 0,
|
||||
// Reserved3 TEXT,
|
||||
// Reserved4 INTEGER DEFAULT 0,
|
||||
// Reserved5 TEXT,
|
||||
// bytesXml BLOB
|
||||
// )
|
||||
type SessionV3 struct {
|
||||
StrUsrName string `json:"strUsrName"`
|
||||
NOrder int `json:"nOrder"`
|
||||
StrNickName string `json:"strNickName"`
|
||||
StrContent string `json:"strContent"`
|
||||
NTime int64 `json:"nTime"`
|
||||
|
||||
// NUnReadCount int `json:"nUnReadCount"`
|
||||
// ParentRef string `json:"parentRef"`
|
||||
// Reserved0 int `json:"Reserved0"`
|
||||
// Reserved1 string `json:"Reserved1"`
|
||||
// NStatus int `json:"nStatus"`
|
||||
// NIsSend int `json:"nIsSend"`
|
||||
// NMsgType int `json:"nMsgType"`
|
||||
// NMsgLocalID int `json:"nMsgLocalID"`
|
||||
// NMsgStatus int `json:"nMsgStatus"`
|
||||
// EditContent string `json:"editContent"`
|
||||
// OthersAtMe int `json:"othersAtMe"`
|
||||
// Reserved2 int `json:"Reserved2"`
|
||||
// Reserved3 string `json:"Reserved3"`
|
||||
// Reserved4 int `json:"Reserved4"`
|
||||
// Reserved5 string `json:"Reserved5"`
|
||||
// BytesXml string `json:"bytesXml"`
|
||||
}
|
||||
|
||||
func (s *SessionV3) Wrap() *Session {
|
||||
return &Session{
|
||||
UserName: s.StrUsrName,
|
||||
NOrder: s.NOrder,
|
||||
NickName: s.StrNickName,
|
||||
Content: s.StrContent,
|
||||
NTime: time.Unix(int64(s.NTime), 0),
|
||||
}
|
||||
}
|
||||
|
||||
// 注意,v4 session 是独立数据库文件
|
||||
// CREATE TABLE SessionTable(
|
||||
// username TEXT PRIMARY KEY,
|
||||
// type INTEGER,
|
||||
// unread_count INTEGER,
|
||||
// unread_first_msg_srv_id INTEGER,
|
||||
// is_hidden INTEGER,
|
||||
// summary TEXT,
|
||||
// draft TEXT,
|
||||
// status INTEGER,
|
||||
// last_timestamp INTEGER,
|
||||
// sort_timestamp INTEGER,
|
||||
// last_clear_unread_timestamp INTEGER,
|
||||
// last_msg_locald_id INTEGER,
|
||||
// last_msg_type INTEGER,
|
||||
// last_msg_sub_type INTEGER,
|
||||
// last_msg_sender TEXT,
|
||||
// last_sender_display_name TEXT,
|
||||
// last_msg_ext_type INTEGER
|
||||
// )
|
||||
type SessionV4 struct {
|
||||
Username string `json:"username"`
|
||||
Summary string `json:"summary"`
|
||||
LastTimestamp int `json:"last_timestamp"`
|
||||
LastMsgSender string `json:"last_msg_sender"`
|
||||
LastSenderDisplayName string `json:"last_sender_display_name"`
|
||||
|
||||
// Type int `json:"type"`
|
||||
// UnreadCount int `json:"unread_count"`
|
||||
// UnreadFirstMsgSrvID int `json:"unread_first_msg_srv_id"`
|
||||
// IsHidden int `json:"is_hidden"`
|
||||
// Draft string `json:"draft"`
|
||||
// Status int `json:"status"`
|
||||
// SortTimestamp int `json:"sort_timestamp"`
|
||||
// LastClearUnreadTimestamp int `json:"last_clear_unread_timestamp"`
|
||||
// LastMsgLocaldID int `json:"last_msg_locald_id"`
|
||||
// LastMsgType int `json:"last_msg_type"`
|
||||
// LastMsgSubType int `json:"last_msg_sub_type"`
|
||||
// LastMsgExtType int `json:"last_msg_ext_type"`
|
||||
}
|
||||
|
||||
func (s *Session) PlainText(limit int) string {
|
||||
buf := strings.Builder{}
|
||||
buf.WriteString(s.NickName)
|
||||
buf.WriteString("(")
|
||||
buf.WriteString(s.UserName)
|
||||
buf.WriteString(") ")
|
||||
buf.WriteString(s.NTime.Format("2006-01-02 15:04:05"))
|
||||
buf.WriteString("\n")
|
||||
if limit > 0 {
|
||||
if len(s.Content) > limit {
|
||||
buf.WriteString(s.Content[:limit])
|
||||
buf.WriteString(" <...>")
|
||||
} else {
|
||||
buf.WriteString(s.Content)
|
||||
}
|
||||
}
|
||||
buf.WriteString("\n")
|
||||
return buf.String()
|
||||
}
|
||||
@@ -1,254 +0,0 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.5
|
||||
// protoc v5.29.3
|
||||
// source: bytesextra.proto
|
||||
|
||||
package wxproto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type BytesExtraHeader struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"`
|
||||
Field2 int32 `protobuf:"varint,2,opt,name=field2,proto3" json:"field2,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BytesExtraHeader) Reset() {
|
||||
*x = BytesExtraHeader{}
|
||||
mi := &file_bytesextra_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BytesExtraHeader) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BytesExtraHeader) ProtoMessage() {}
|
||||
|
||||
func (x *BytesExtraHeader) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_bytesextra_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BytesExtraHeader.ProtoReflect.Descriptor instead.
|
||||
func (*BytesExtraHeader) Descriptor() ([]byte, []int) {
|
||||
return file_bytesextra_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *BytesExtraHeader) GetField1() int32 {
|
||||
if x != nil {
|
||||
return x.Field1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BytesExtraHeader) GetField2() int32 {
|
||||
if x != nil {
|
||||
return x.Field2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type BytesExtraItem struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Type int32 `protobuf:"varint,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BytesExtraItem) Reset() {
|
||||
*x = BytesExtraItem{}
|
||||
mi := &file_bytesextra_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BytesExtraItem) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BytesExtraItem) ProtoMessage() {}
|
||||
|
||||
func (x *BytesExtraItem) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_bytesextra_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BytesExtraItem.ProtoReflect.Descriptor instead.
|
||||
func (*BytesExtraItem) Descriptor() ([]byte, []int) {
|
||||
return file_bytesextra_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *BytesExtraItem) GetType() int32 {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *BytesExtraItem) GetValue() string {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type BytesExtra struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Header *BytesExtraHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
|
||||
Items []*BytesExtraItem `protobuf:"bytes,3,rep,name=items,proto3" json:"items,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BytesExtra) Reset() {
|
||||
*x = BytesExtra{}
|
||||
mi := &file_bytesextra_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BytesExtra) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BytesExtra) ProtoMessage() {}
|
||||
|
||||
func (x *BytesExtra) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_bytesextra_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BytesExtra.ProtoReflect.Descriptor instead.
|
||||
func (*BytesExtra) Descriptor() ([]byte, []int) {
|
||||
return file_bytesextra_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *BytesExtra) GetHeader() *BytesExtraHeader {
|
||||
if x != nil {
|
||||
return x.Header
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *BytesExtra) GetItems() []*BytesExtraItem {
|
||||
if x != nil {
|
||||
return x.Items
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_bytesextra_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_bytesextra_proto_rawDesc = string([]byte{
|
||||
0x0a, 0x10, 0x62, 0x79, 0x74, 0x65, 0x73, 0x65, 0x78, 0x74, 0x72, 0x61, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x12, 0x0c, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x22, 0x42, 0x0a, 0x10, 0x42, 0x79, 0x74, 0x65, 0x73, 0x45, 0x78, 0x74, 0x72, 0x61, 0x48, 0x65,
|
||||
0x61, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x31, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x66, 0x69, 0x65, 0x6c, 0x64, 0x32, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x66, 0x69,
|
||||
0x65, 0x6c, 0x64, 0x32, 0x22, 0x3a, 0x0a, 0x0e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x45, 0x78, 0x74,
|
||||
0x72, 0x61, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x22, 0x78, 0x0a, 0x0a, 0x42, 0x79, 0x74, 0x65, 0x73, 0x45, 0x78, 0x74, 0x72, 0x61, 0x12, 0x36,
|
||||
0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e,
|
||||
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79,
|
||||
0x74, 0x65, 0x73, 0x45, 0x78, 0x74, 0x72, 0x61, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x06,
|
||||
0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18,
|
||||
0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x45, 0x78, 0x74, 0x72, 0x61, 0x49,
|
||||
0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x3b,
|
||||
0x77, 0x78, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
})
|
||||
|
||||
var (
|
||||
file_bytesextra_proto_rawDescOnce sync.Once
|
||||
file_bytesextra_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_bytesextra_proto_rawDescGZIP() []byte {
|
||||
file_bytesextra_proto_rawDescOnce.Do(func() {
|
||||
file_bytesextra_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_bytesextra_proto_rawDesc), len(file_bytesextra_proto_rawDesc)))
|
||||
})
|
||||
return file_bytesextra_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_bytesextra_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_bytesextra_proto_goTypes = []any{
|
||||
(*BytesExtraHeader)(nil), // 0: app.protobuf.BytesExtraHeader
|
||||
(*BytesExtraItem)(nil), // 1: app.protobuf.BytesExtraItem
|
||||
(*BytesExtra)(nil), // 2: app.protobuf.BytesExtra
|
||||
}
|
||||
var file_bytesextra_proto_depIdxs = []int32{
|
||||
0, // 0: app.protobuf.BytesExtra.header:type_name -> app.protobuf.BytesExtraHeader
|
||||
1, // 1: app.protobuf.BytesExtra.items:type_name -> app.protobuf.BytesExtraItem
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_bytesextra_proto_init() }
|
||||
func file_bytesextra_proto_init() {
|
||||
if File_bytesextra_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_bytesextra_proto_rawDesc), len(file_bytesextra_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_bytesextra_proto_goTypes,
|
||||
DependencyIndexes: file_bytesextra_proto_depIdxs,
|
||||
MessageInfos: file_bytesextra_proto_msgTypes,
|
||||
}.Build()
|
||||
File_bytesextra_proto = out.File
|
||||
file_bytesextra_proto_goTypes = nil
|
||||
file_bytesextra_proto_depIdxs = nil
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
syntax = "proto3";
|
||||
package app.protobuf;
|
||||
option go_package=".;wxproto";
|
||||
|
||||
message BytesExtraHeader {
|
||||
int32 field1 = 1;
|
||||
int32 field2 = 2;
|
||||
}
|
||||
|
||||
message BytesExtraItem {
|
||||
int32 type = 1;
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
message BytesExtra {
|
||||
BytesExtraHeader header = 1;
|
||||
repeated BytesExtraItem items = 3;
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
// v3 & v4 通用,可能会有部分字段差异
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.5
|
||||
// protoc v5.29.3
|
||||
// source: roomdata.proto
|
||||
|
||||
package wxproto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type RoomData struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Users []*RoomDataUser `protobuf:"bytes,1,rep,name=users,proto3" json:"users,omitempty"`
|
||||
RoomCap *int32 `protobuf:"varint,5,opt,name=roomCap,proto3,oneof" json:"roomCap,omitempty"` // 只在第一份数据中出现,值为500
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RoomData) Reset() {
|
||||
*x = RoomData{}
|
||||
mi := &file_roomdata_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RoomData) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RoomData) ProtoMessage() {}
|
||||
|
||||
func (x *RoomData) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_roomdata_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RoomData.ProtoReflect.Descriptor instead.
|
||||
func (*RoomData) Descriptor() ([]byte, []int) {
|
||||
return file_roomdata_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *RoomData) GetUsers() []*RoomDataUser {
|
||||
if x != nil {
|
||||
return x.Users
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *RoomData) GetRoomCap() int32 {
|
||||
if x != nil && x.RoomCap != nil {
|
||||
return *x.RoomCap
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type RoomDataUser struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
UserName string `protobuf:"bytes,1,opt,name=userName,proto3" json:"userName,omitempty"` // 用户ID或名称
|
||||
DisplayName *string `protobuf:"bytes,2,opt,name=displayName,proto3,oneof" json:"displayName,omitempty"` // 显示名称,可能是UTF-8编码的中文,部分记录可能为空
|
||||
Status int32 `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"` // 状态码,值范围0-9
|
||||
Inviter *string `protobuf:"bytes,4,opt,name=inviter,proto3,oneof" json:"inviter,omitempty"` // 邀请人
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RoomDataUser) Reset() {
|
||||
*x = RoomDataUser{}
|
||||
mi := &file_roomdata_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RoomDataUser) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RoomDataUser) ProtoMessage() {}
|
||||
|
||||
func (x *RoomDataUser) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_roomdata_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RoomDataUser.ProtoReflect.Descriptor instead.
|
||||
func (*RoomDataUser) Descriptor() ([]byte, []int) {
|
||||
return file_roomdata_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *RoomDataUser) GetUserName() string {
|
||||
if x != nil {
|
||||
return x.UserName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomDataUser) GetDisplayName() string {
|
||||
if x != nil && x.DisplayName != nil {
|
||||
return *x.DisplayName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomDataUser) GetStatus() int32 {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RoomDataUser) GetInviter() string {
|
||||
if x != nil && x.Inviter != nil {
|
||||
return *x.Inviter
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_roomdata_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_roomdata_proto_rawDesc = string([]byte{
|
||||
0x0a, 0x0e, 0x72, 0x6f, 0x6f, 0x6d, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x12, 0x0c, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x22, 0x67,
|
||||
0x0a, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, 0x05, 0x75, 0x73,
|
||||
0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x44, 0x61, 0x74,
|
||||
0x61, 0x55, 0x73, 0x65, 0x72, 0x52, 0x05, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x07,
|
||||
0x72, 0x6f, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x48, 0x00, 0x52,
|
||||
0x07, 0x72, 0x6f, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, 0x08, 0x5f,
|
||||
0x72, 0x6f, 0x6f, 0x6d, 0x43, 0x61, 0x70, 0x22, 0xa4, 0x01, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d,
|
||||
0x44, 0x61, 0x74, 0x61, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x69, 0x73,
|
||||
0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x16, 0x0a, 0x06, 0x73,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x12, 0x1d, 0x0a, 0x07, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x07, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x88,
|
||||
0x01, 0x01, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61,
|
||||
0x6d, 0x65, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x69, 0x6e, 0x76, 0x69, 0x74, 0x65, 0x72, 0x42, 0x0b,
|
||||
0x5a, 0x09, 0x2e, 0x3b, 0x77, 0x78, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x33,
|
||||
})
|
||||
|
||||
var (
|
||||
file_roomdata_proto_rawDescOnce sync.Once
|
||||
file_roomdata_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_roomdata_proto_rawDescGZIP() []byte {
|
||||
file_roomdata_proto_rawDescOnce.Do(func() {
|
||||
file_roomdata_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_roomdata_proto_rawDesc), len(file_roomdata_proto_rawDesc)))
|
||||
})
|
||||
return file_roomdata_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_roomdata_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_roomdata_proto_goTypes = []any{
|
||||
(*RoomData)(nil), // 0: app.protobuf.RoomData
|
||||
(*RoomDataUser)(nil), // 1: app.protobuf.RoomDataUser
|
||||
}
|
||||
var file_roomdata_proto_depIdxs = []int32{
|
||||
1, // 0: app.protobuf.RoomData.users:type_name -> app.protobuf.RoomDataUser
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_roomdata_proto_init() }
|
||||
func file_roomdata_proto_init() {
|
||||
if File_roomdata_proto != nil {
|
||||
return
|
||||
}
|
||||
file_roomdata_proto_msgTypes[0].OneofWrappers = []any{}
|
||||
file_roomdata_proto_msgTypes[1].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_roomdata_proto_rawDesc), len(file_roomdata_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_roomdata_proto_goTypes,
|
||||
DependencyIndexes: file_roomdata_proto_depIdxs,
|
||||
MessageInfos: file_roomdata_proto_msgTypes,
|
||||
}.Build()
|
||||
File_roomdata_proto = out.File
|
||||
file_roomdata_proto_goTypes = nil
|
||||
file_roomdata_proto_depIdxs = nil
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// v3 & v4 通用,可能会有部分字段差异
|
||||
syntax = "proto3";
|
||||
package app.protobuf;
|
||||
option go_package=".;wxproto";
|
||||
|
||||
message RoomData {
|
||||
repeated RoomDataUser users = 1;
|
||||
optional int32 roomCap = 5; // 只在第一份数据中出现,值为500
|
||||
}
|
||||
|
||||
message RoomDataUser {
|
||||
string userName = 1; // 用户ID或名称
|
||||
optional string displayName = 2; // 显示名称,可能是UTF-8编码的中文,部分记录可能为空
|
||||
int32 status = 3; // 状态码,值范围0-9
|
||||
optional string inviter = 4; // 邀请人
|
||||
}
|
||||
11
pkg/util/zstd/zstd.go
Normal file
11
pkg/util/zstd/zstd.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package zstd
|
||||
|
||||
import (
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
var decoder, _ = zstd.NewReader(nil, zstd.WithDecoderConcurrency(0))
|
||||
|
||||
func Decompress(src []byte) ([]byte, error) {
|
||||
return decoder.DecodeAll(src, nil)
|
||||
}
|
||||
Reference in New Issue
Block a user