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 }