github.com/Ptt-official-app/go-bbs@v0.12.0/pttbbs/userinfo.go (about)

     1  package pttbbs
     2  
     3  import (
     4  	"encoding/binary"
     5  	"io"
     6  	"log"
     7  	"os"
     8  	"time"
     9  )
    10  
    11  const (
    12  	PosOfUserInfoUID      = 0
    13  	PosOfUserInfoPID      = PosOfUserInfoUID + 4
    14  	PosOfUserInfoSockAddr = PosOfUserInfoPID + 4
    15  
    16  	PosOfUserInfoUserLevel  = PosOfUserInfoSockAddr + 4
    17  	PosOfUserInfoUserID     = PosOfUserInfoUserLevel + 4
    18  	PosOfUserInfoNickname   = PosOfUserInfoUserID + IDLength + 1
    19  	PosOfUserInfoFrom       = PosOfUserInfoNickname + NicknameSize
    20  	PosOfUserInfoFromIP     = PosOfUserInfoFrom + MachineNameLength
    21  	PosOfUserInfoDarkWin    = PosOfUserInfoFromIP + 4
    22  	PosOfUserInfoDarkLose   = PosOfUserInfoDarkWin + 2
    23  	PosOfUserInfoAngelPause = PosOfUserInfoDarkLose + 2 + 1 // gap_0
    24  	PosOfUserInfoDarkTie    = PosOfUserInfoAngelPause + 1
    25  
    26  	PosOfUserInfoFriendTotal = PosOfUserInfoDarkTie + 2
    27  	PosOfUserInfoNumFriends  = PosOfUserInfoFriendTotal + 4
    28  
    29  	PosOfUserInfoMyFriend     = PosOfUserInfoNumFriends + 2 + 2             // _unused3
    30  	PosOfUserInfoFriendOnline = PosOfUserInfoMyFriend + MaxFriend*4 + 4     // gap_1
    31  	PosOfUserInfoReject       = PosOfUserInfoFriendOnline + MaxFriend*4 + 4 // gap_2
    32  
    33  	PosOfUserInfoMsgCount = PosOfUserInfoReject + MaxReject*4 + 4 // gap_3
    34  	PosOfUserInfoMsgs     = PosOfUserInfoMsgCount + 1 + 3         // _unused4
    35  
    36  	PosOfUserInfoBirth     = PosOfUserInfoMsgs + MaxMsgs*100 + 100 // gap_4 and 100 is the size of msgque_t when run on my machine
    37  	PosOfUserInfoActive    = PosOfUserInfoBirth + 1
    38  	PosOfUserInfoInvisible = PosOfUserInfoActive + 1
    39  	PosOfUserInfoMode      = PosOfUserInfoInvisible + 1
    40  	PosOfUserInfoPager     = PosOfUserInfoMode + 1
    41  
    42  	PosOfUserInfoConn6Win  = PosOfUserInfoPager + 1 + 1 // unused5
    43  	PosOfUserInfoLastAct   = PosOfUserInfoConn6Win + 2
    44  	PosOfUserInfoAlerts    = PosOfUserInfoLastAct + 4
    45  	PosOfUserInfoConn6Lose = PosOfUserInfoAlerts + 1 + 1 // unused_mind
    46  
    47  	PosOfUserInfoSig        = PosOfUserInfoConn6Lose + 2 + 1 // unused_mind2
    48  	PosOfUserInfoConn6Tie   = PosOfUserInfoSig + 1
    49  	PosOfUserInfoDestUID    = PosOfUserInfoConn6Tie + 2
    50  	PosOfUserInfoDestUIP    = PosOfUserInfoDestUID + 4
    51  	PosOfUserInfoSockActive = PosOfUserInfoDestUIP + 4
    52  
    53  	PosOfUserInfoInChat = PosOfUserInfoSockActive + 1
    54  	PosOfUserInfoChatID = PosOfUserInfoInChat + 1
    55  
    56  	PosOfUserInfoLockMode = PosOfUserInfoChatID + ChatIDLength
    57  	PosOfUserInfoTurn     = PosOfUserInfoLockMode + 1
    58  	PosOfUserInfoMateID   = PosOfUserInfoTurn + 1
    59  	PosOfUserInfoColor    = PosOfUserInfoMateID + IDLength + 1
    60  
    61  	PosOfUserInfoFiveWin        = PosOfUserInfoColor + 1
    62  	PosOfUserInfoFiveLose       = PosOfUserInfoFiveWin + 2
    63  	PosOfUserInfoFiveTie        = PosOfUserInfoFiveLose + 2
    64  	PosOfUserInfoChcWin         = PosOfUserInfoFiveTie + 2
    65  	PosOfUserInfoChcLose        = PosOfUserInfoChcWin + 2
    66  	PosOfUserInfoChcTie         = PosOfUserInfoFiveLose + 2
    67  	PosOfUserInfoChessEloRating = PosOfUserInfoChcTie + 2
    68  	PosOfUserInfoGoWin          = PosOfUserInfoChessEloRating + 2
    69  	PosOfUserInfoGoLose         = PosOfUserInfoGoWin + 2
    70  	PosOfUserInfoGoTie          = PosOfUserInfoGoLose + 2
    71  
    72  	PosOfUserInfoWithMe = PosOfUserInfoGoTie + 2
    73  	PosOfUserInfoBrcID  = PosOfUserInfoWithMe + 4
    74  
    75  	PosOfUserInfoWBTime = PosOfUserInfoBrcID + 4
    76  )
    77  
    78  // UserInfoCache is `userinfo_t` in pttstruct.h, all of those object will be store in shared memory
    79  type UserInfoCache struct {
    80  	uid      int32
    81  	pid      int32
    82  	SockAddr int32
    83  
    84  	UserLevel uint32
    85  	userID    string
    86  	nickname  string
    87  	from      string // machine name the user called in from
    88  	fromIP    uint32
    89  
    90  	DarkChess  GameScore
    91  	AngelPause uint8
    92  
    93  	FriendTotal int32
    94  	NumFriends  int16
    95  
    96  	MyFriend     [MaxFriend]int32
    97  	FriendOnline [MaxFriend]uint32
    98  
    99  	Reject [MaxReject]int32
   100  
   101  	MsgCount uint8
   102  	Msgs     [MaxMsgs]MessageQueueCache
   103  
   104  	Birth     bool // whether it's birthday today
   105  	Active    bool
   106  	Invisible bool
   107  	Mode      uint8
   108  	Pager     bool
   109  
   110  	Conn6   GameScore
   111  	LastAct time.Time
   112  	Alerts  uint8 // mail alert, passwd update ...
   113  
   114  	Signature  uint8
   115  	DestUID    int32
   116  	DestUIP    int32
   117  	SockActive uint8
   118  
   119  	InChat uint8
   120  	ChatID string
   121  
   122  	LockMode uint8
   123  	Turn     bool
   124  	MateID   string
   125  	Color    uint8
   126  
   127  	// game record
   128  	Five           GameScore
   129  	ChineseChess   GameScore
   130  	ChessEloRating uint16
   131  	GoChess        GameScore
   132  
   133  	WithMe uint32
   134  	brcID  uint32
   135  
   136  	wbTime time.Time // not sure if this is present
   137  }
   138  
   139  // function used for testing unmarshal and marshal function
   140  func OpenUserInfoCache(filename string) ([]*UserInfoCache, error) {
   141  	file, err := os.Open(filename)
   142  	if err != nil {
   143  		log.Println(err)
   144  		return nil, err
   145  	}
   146  
   147  	ret := []*UserInfoCache{}
   148  
   149  	for {
   150  		buf := make([]byte, 3484)
   151  
   152  		_, err := file.Read(buf)
   153  		if err == io.EOF {
   154  			break
   155  		} else if err != nil {
   156  			log.Println(err)
   157  			return nil, err
   158  		}
   159  
   160  		cache := UnmarshalUserInfo(buf)
   161  
   162  		ret = append(ret, cache)
   163  	}
   164  
   165  	return ret, nil
   166  }
   167  
   168  func UnmarshalUserInfo(data []byte) *UserInfoCache {
   169  	cache := &UserInfoCache{}
   170  
   171  	cache.uid = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoUID : PosOfUserInfoUID+4]))
   172  	cache.pid = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoPID : PosOfUserInfoPID+4]))
   173  	cache.SockAddr = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoSockAddr : PosOfUserInfoSockAddr+4]))
   174  
   175  	cache.UserLevel = binary.LittleEndian.Uint32(data[PosOfUserInfoUserLevel : PosOfUserInfoUserLevel+4])
   176  	cache.userID = newStringFormCString(data[PosOfUserInfoUserID : PosOfUserInfoUserID+IDLength+1])
   177  	cache.nickname = newStringFormBig5UAOCString(data[PosOfUserInfoNickname : PosOfUserInfoNickname+NicknameSize])
   178  	cache.from = newStringFormCString(data[PosOfUserInfoFrom : PosOfUserInfoFrom+MachineNameLength])
   179  	cache.fromIP = binary.LittleEndian.Uint32(data[PosOfUserInfoFromIP : PosOfUserInfoFromIP+4])
   180  	cache.DarkChess.Win = binary.LittleEndian.Uint16(data[PosOfUserInfoDarkWin : PosOfUserInfoDarkWin+2])
   181  	cache.DarkChess.Lose = binary.LittleEndian.Uint16(data[PosOfUserInfoDarkLose : PosOfUserInfoDarkLose+2])
   182  	cache.AngelPause = data[PosOfUserInfoAngelPause]
   183  	cache.DarkChess.Tie = binary.LittleEndian.Uint16(data[PosOfUserInfoDarkTie : PosOfUserInfoDarkTie+2])
   184  
   185  	cache.FriendTotal = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoFriendTotal : PosOfUserInfoFriendTotal+4]))
   186  	cache.NumFriends = int16(binary.LittleEndian.Uint16(data[PosOfUserInfoNumFriends : PosOfUserInfoNumFriends+2]))
   187  
   188  	for idx := range cache.MyFriend {
   189  		cache.MyFriend[idx] = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoMyFriend+4*idx : PosOfUserInfoMyFriend+4*idx+4]))
   190  	}
   191  
   192  	for idx := range cache.FriendOnline {
   193  		cache.FriendOnline[idx] = binary.LittleEndian.Uint32(data[PosOfUserInfoFriendOnline+4*idx : PosOfUserInfoFriendOnline+4*idx+4])
   194  	}
   195  
   196  	for idx := range cache.Reject {
   197  		cache.Reject[idx] = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoReject+4*idx : PosOfUserInfoReject+4*idx+4]))
   198  	}
   199  
   200  	cache.MsgCount = data[PosOfUserInfoMsgCount]
   201  
   202  	for idx := range cache.Msgs {
   203  		// Todo: replace it with the Unmarshal for MessageQueueCache
   204  		cache.Msgs[idx] = data[PosOfUserInfoMsgs+100*idx : PosOfUserInfoMsgs+100*idx+100]
   205  	}
   206  
   207  	cache.Birth = (data[PosOfUserInfoBirth] != 0)
   208  	cache.Active = (data[PosOfUserInfoActive] != 0)
   209  	cache.Invisible = (data[PosOfUserInfoInvisible] != 0)
   210  	cache.Mode = data[PosOfUserInfoMode]
   211  	cache.Pager = (data[PosOfUserInfoPager] != 0)
   212  
   213  	cache.Conn6.Win = binary.LittleEndian.Uint16(data[PosOfUserInfoConn6Win : PosOfUserInfoConn6Win+2])
   214  	cache.LastAct = time.Unix(int64(binary.LittleEndian.Uint32(data[PosOfUserInfoLastAct:PosOfUserInfoLastAct+4])), 0)
   215  	cache.Alerts = data[PosOfUserInfoAlerts]
   216  	cache.Conn6.Lose = binary.LittleEndian.Uint16(data[PosOfUserInfoConn6Lose : PosOfUserInfoConn6Lose+2])
   217  
   218  	cache.Signature = data[PosOfUserInfoSig]
   219  	cache.Conn6.Tie = binary.LittleEndian.Uint16(data[PosOfUserInfoConn6Tie : PosOfUserInfoConn6Tie+2])
   220  
   221  	cache.DestUID = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoDestUID : PosOfUserInfoDestUID+4]))
   222  	cache.DestUIP = int32(binary.LittleEndian.Uint32(data[PosOfUserInfoDestUIP : PosOfUserInfoDestUIP+4]))
   223  	cache.SockActive = data[PosOfUserInfoSockActive]
   224  
   225  	cache.InChat = data[PosOfUserInfoInChat]
   226  	cache.ChatID = newStringFormCString(data[PosOfUserInfoChatID : PosOfUserInfoChatID+ChatIDLength])
   227  
   228  	cache.LockMode = data[PosOfUserInfoLockMode]
   229  	cache.Turn = (data[PosOfUserInfoTurn] != 0)
   230  
   231  	cache.MateID = newStringFormBig5UAOCString(data[PosOfUserInfoMateID : PosOfUserInfoMateID+IDLength+1])
   232  	cache.Color = data[PosOfUserInfoColor]
   233  
   234  	cache.Five.Win = binary.LittleEndian.Uint16(data[PosOfUserInfoFiveWin : PosOfUserInfoFiveWin+2])
   235  	cache.Five.Lose = binary.LittleEndian.Uint16(data[PosOfUserInfoFiveLose : PosOfUserInfoFiveLose+2])
   236  	cache.Five.Tie = binary.LittleEndian.Uint16(data[PosOfUserInfoFiveTie : PosOfUserInfoFiveTie+2])
   237  
   238  	cache.ChineseChess.Win = binary.LittleEndian.Uint16(data[PosOfUserInfoChcWin : PosOfUserInfoChcWin+2])
   239  	cache.ChineseChess.Lose = binary.LittleEndian.Uint16(data[PosOfUserInfoChcLose : PosOfUserInfoChcLose+2])
   240  	cache.ChineseChess.Tie = binary.LittleEndian.Uint16(data[PosOfUserInfoChcTie : PosOfUserInfoChcTie+2])
   241  
   242  	cache.ChessEloRating = binary.LittleEndian.Uint16(data[PosOfUserInfoChessEloRating : PosOfUserInfoChessEloRating+2])
   243  
   244  	cache.GoChess.Win = binary.LittleEndian.Uint16(data[PosOfUserInfoGoWin : PosOfUserInfoGoWin+2])
   245  	cache.GoChess.Lose = binary.LittleEndian.Uint16(data[PosOfUserInfoGoLose : PosOfUserInfoGoLose+2])
   246  	cache.GoChess.Tie = binary.LittleEndian.Uint16(data[PosOfUserInfoGoTie : PosOfUserInfoGoTie+2])
   247  
   248  	cache.WithMe = binary.LittleEndian.Uint32(data[PosOfUserInfoWithMe : PosOfUserInfoWithMe+4])
   249  	cache.brcID = binary.LittleEndian.Uint32(data[PosOfUserInfoBrcID : PosOfUserInfoBrcID+4])
   250  
   251  	cache.wbTime = time.Unix(int64(binary.LittleEndian.Uint32(data[PosOfUserInfoWBTime:PosOfUserInfoWBTime+4])), 0)
   252  	return cache
   253  }
   254  
   255  func (u *UserInfoCache) MarshalBinary() []byte {
   256  	ret := make([]byte, 3484)
   257  
   258  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoUID:PosOfUserInfoUID+4], uint32(u.uid))
   259  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoPID:PosOfUserInfoPID+4], uint32(u.pid))
   260  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoSockAddr:PosOfUserInfoSockAddr+4], uint32(u.SockAddr))
   261  
   262  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoUserLevel:PosOfUserInfoUserLevel+4], u.UserLevel)
   263  
   264  	copy(ret[PosOfUserInfoUserID:PosOfUserInfoUserID+IDLength+1], utf8ToBig5UAOString(u.userID))
   265  	copy(ret[PosOfUserInfoNickname:PosOfUserInfoNickname+NicknameSize], utf8ToBig5UAOString(u.nickname))
   266  	copy(ret[PosOfUserInfoFrom:PosOfUserInfoFrom+MachineNameLength], utf8ToBig5UAOString(u.from))
   267  
   268  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoFromIP:PosOfUserInfoFromIP+4], u.fromIP)
   269  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoDarkWin:PosOfUserInfoDarkWin+2], u.DarkChess.Win)
   270  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoDarkLose:PosOfUserInfoDarkLose+2], u.DarkChess.Lose)
   271  
   272  	ret[PosOfUserInfoAngelPause] = u.AngelPause
   273  
   274  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoDarkTie:PosOfUserInfoDarkTie+2], u.DarkChess.Tie)
   275  
   276  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoFriendTotal:PosOfUserInfoFriendTotal+4], uint32(u.FriendTotal))
   277  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoNumFriends:PosOfUserInfoNumFriends+2], uint16(u.NumFriends))
   278  
   279  	for idx, val := range u.MyFriend {
   280  		binary.LittleEndian.PutUint32(ret[PosOfUserInfoMyFriend+4*idx:PosOfUserInfoMyFriend+4*idx+4], uint32(val))
   281  	}
   282  
   283  	for idx, val := range u.FriendOnline {
   284  		binary.LittleEndian.PutUint32(ret[PosOfUserInfoFriendOnline+4*idx:PosOfUserInfoFriendOnline+4*idx+4], uint32(val))
   285  	}
   286  
   287  	for idx, val := range u.Reject {
   288  		binary.LittleEndian.PutUint32(ret[PosOfUserInfoReject+4*idx:PosOfUserInfoReject+4*idx+4], uint32(val))
   289  	}
   290  
   291  	ret[PosOfUserInfoMsgCount] = u.MsgCount
   292  
   293  	for idx, val := range u.Msgs {
   294  		// Todo: replace it with the MarshalBinary for MessageQueueCache
   295  		copy(ret[PosOfUserInfoMsgs+100*idx:PosOfUserInfoMsgs+100*idx+100], val)
   296  	}
   297  
   298  	if u.Birth {
   299  		ret[PosOfUserInfoBirth] = 1
   300  	} else {
   301  		ret[PosOfUserInfoBirth] = 0
   302  	}
   303  
   304  	if u.Active {
   305  		ret[PosOfUserInfoActive] = 1
   306  	} else {
   307  		ret[PosOfUserInfoActive] = 0
   308  	}
   309  	if u.Invisible {
   310  		ret[PosOfUserInfoInvisible] = 1
   311  	} else {
   312  		ret[PosOfUserInfoInvisible] = 0
   313  	}
   314  
   315  	ret[PosOfUserInfoMode] = u.Mode
   316  
   317  	if u.Pager {
   318  		ret[PosOfUserInfoPager] = 1
   319  	} else {
   320  		ret[PosOfUserInfoPager] = 0
   321  	}
   322  
   323  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoConn6Win:PosOfUserInfoConn6Win+2], u.Conn6.Win)
   324  
   325  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoLastAct:PosOfUserInfoLastAct+4], uint32(u.LastAct.Unix()))
   326  	ret[PosOfUserInfoAlerts] = u.Alerts
   327  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoConn6Lose:PosOfUserInfoConn6Lose+2], u.Conn6.Lose)
   328  
   329  	ret[PosOfUserInfoSig] = u.Signature
   330  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoConn6Tie:PosOfUserInfoConn6Tie+2], u.Conn6.Tie)
   331  
   332  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoDestUID:PosOfUserInfoDestUID+4], uint32(u.DestUID))
   333  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoDestUIP:PosOfUserInfoDestUIP+4], uint32(u.DestUIP))
   334  
   335  	ret[PosOfUserInfoSockActive] = u.SockActive
   336  	ret[PosOfUserInfoInChat] = u.InChat
   337  	copy(ret[PosOfUserInfoChatID:PosOfUserInfoChatID+ChatIDLength], utf8ToBig5UAOString(u.ChatID))
   338  
   339  	ret[PosOfUserInfoLockMode] = u.LockMode
   340  
   341  	if u.Turn {
   342  		ret[PosOfUserInfoTurn] = 1
   343  	} else {
   344  		ret[PosOfUserInfoTurn] = 0
   345  	}
   346  
   347  	copy(ret[PosOfUserInfoMateID:PosOfUserInfoMateID+IDLength+1], utf8ToBig5UAOString(u.MateID))
   348  
   349  	ret[PosOfUserInfoColor] = u.Color
   350  
   351  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoFiveWin:PosOfUserInfoFiveWin+2], u.Five.Win)
   352  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoFiveLose:PosOfUserInfoFiveLose+2], u.Five.Lose)
   353  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoFiveTie:PosOfUserInfoFiveTie+2], u.Five.Tie)
   354  
   355  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoChcWin:PosOfUserInfoChcWin+2], u.ChineseChess.Win)
   356  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoChcLose:PosOfUserInfoChcLose+2], u.ChineseChess.Lose)
   357  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoChcTie:PosOfUserInfoChcTie+2], u.ChineseChess.Tie)
   358  
   359  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoChessEloRating:PosOfUserInfoChessEloRating+2], u.ChessEloRating)
   360  
   361  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoGoWin:PosOfUserInfoGoWin+2], u.GoChess.Win)
   362  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoGoLose:PosOfUserInfoGoLose+2], u.GoChess.Lose)
   363  	binary.LittleEndian.PutUint16(ret[PosOfUserInfoGoTie:PosOfUserInfoGoTie+2], u.GoChess.Tie)
   364  
   365  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoWithMe:PosOfUserInfoWithMe+4], u.WithMe)
   366  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoBrcID:PosOfUserInfoBrcID+4], u.brcID)
   367  
   368  	binary.LittleEndian.PutUint32(ret[PosOfUserInfoWBTime:PosOfUserInfoWBTime+4], uint32(u.wbTime.Unix()))
   369  
   370  	return ret
   371  
   372  }