func CreateSession(conns net.Conn, imDB imdatabase.ImDb) *Session { //sqlerr := make(chan (error)) //当数据库读写出错,则返回nil,ErrorMysql ClientSession := setSession(conns) //初始化session publicPacket := MakePacket(PublicCMD, 0) //type=0的包 也就是发公钥的包 ClientSession.outgoing <- *publicPacket //首先把RSA的Public Key 发过去 for { //等待一定时间 回馈包,里面要求 username,appkey,aeskey。时间超过,或者里面内容不符合直接关掉conn select { case requestPacket := <-ClientSession.incoming: { //对进来的包进行检验 //isloged, userUid := receiveLoginPacket(ClientSession, requestPacket) if requestPacket.GetType() != 1 { *returnCMD.Sender = 0 *returnCMD.Receiver = 1 *returnCMD.Message.Data = "1:Please login first!" returnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *returnPacket //ImServerLog("A user didn't use a type 1 packet to login.") break } //if requestPacket.GetType() == 1 { //mean that this is a requestPacket requestCMD, err := GetCommand(&requestPacket) //Type=1的包,包含uid+APPKEY+AESKEY if err != nil { //回馈?? ImServerLog("RequestCMD get login command error ", err) /////////////////////////////////////////// break } //验证名字是否登陆了,验证APPKEY是否正确,如果都正确,纪录AESKEY,返回AESKEY加密的回馈包:uid appKey := requestCMD.Message.GetPassword() userUid := requestCMD.GetSender() token := requestCMD.Message.GetName() random := requestCMD.Message.GetRandom() aesKey := requestCMD.Message.GetData() //先看有没token _, fla := UserTable[userUid] if fla == false { //fmt.Println("*****************************用户不存在") //用户未先登录业务服务器 ClientSession.packetReader.AESKEY = []byte(aesKey) ClientSession.packetWriter.AESKEY = []byte(aesKey) *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random *returnCMD.Message.Data = "1:User don't login successfully!" notokenreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *notokenreturnPacket break } var userToken string userToken = UserTable[userUid].AToken if appKey != APPKEY || token != userToken { *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random *returnCMD.Message.Data = "1:Wrong AppKey or Token." wrongkeyreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *wrongkeyreturnPacket break } //if appKey == APPKEY && token == userToken { //have the same appkey and online and have the same token //从这里开始可以对imDB操作 ClientSession.packetReader.AESKEY = []byte(aesKey) ClientSession.packetWriter.AESKEY = []byte(aesKey) ClientSession.uid = userUid //如果存在旧的session tcp 则先关掉旧的,释放tcp资源 oldSession, flags := SessionTable[userUid] if flags == true { *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random *returnCMD.Message.Data = "1:Old session is replacing" placingreturnPacket := MakePacket(returnCMD, 3) oldSession.outgoing <- *placingreturnPacket SessionTable[userUid].quit() ImServerLog("User: "******" has logined before. Quit the earlier session.") ////////////////////////////////////////////// } SessionTable[userUid] = ClientSession UserTable[userUid] = Token{UserTable[userUid].AToken, 1} *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random *returnCMD.Message.Data = "1:Connect successfully." successreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *successreturnPacket //********************************************************************************* //goThroughOutLineMessage(userUid, imDB) outLineMessageTableFromSql, err := imDB.Db.Query("select type,packet,timestamp from outlinemessage where receiver_id=? order by timestamp asc", userUid) if err != nil { DatabaseLog("database error in prepare reading outlinemesssage:" + err.Error()) } defer outLineMessageTableFromSql.Close() if err == nil { //DatabaseLog("select from outlinemessage receiver_id = ", userUid) //在离线表找到数据 var outLineMsgType uint32 var outLineMsgePacket []byte var outLineMsgTime string //切片存储所有扫描出来的离线包信息 var allOutLineMsgType []uint32 var allOutLineMsgePacket []string //string类型 //var allOutLineMsgTime []string allOutLineMsgType = make([]uint32, 0, MaxOutLineMsg) allOutLineMsgePacket = make([]string, 0, MaxOutLineMsg) //allOutLineMsgTime = make([]string, 0, MaxOutLineMsg) for outLineMessageTableFromSql.Next() { err := outLineMessageTableFromSql.Scan(&outLineMsgType, &outLineMsgePacket, &outLineMsgTime) if err != nil { DatabaseLog("database error in reading outlinemesssage:" + err.Error()) continue } allOutLineMsgType = append(allOutLineMsgType, outLineMsgType) allOutLineMsgePacket = append(allOutLineMsgePacket, string(outLineMsgePacket)) } outLineMessageTableFromSql.Close() for i, _ := range allOutLineMsgType { var outLinePacket Packet outLinePacket.SetType(allOutLineMsgType[i]) outLinePacket.SetData([]byte(allOutLineMsgePacket[i])) outLineCMD, err := GetCommand(&outLinePacket) if err != nil { ImServerLog("Outlinemessage GetCommand err : ", err) continue } *outLineCMD.Message.Random = GenRandom() outPacket := MakePacket(outLineCMD, outLinePacket.GetType()) _, fl := SessionTable[userUid] if fl { SessionTable[userUid].outgoing <- *outPacket } } err = imDB.DeleteDbTable("delete from outlinemessage where receiver_id=?", userUid) if err != nil { DatabaseLog("Delete from outlinemessage error", err) } } //ImBusinessLog("Delete outlinemessage receiver_id = ", userUid) //return true //if isGetOutLineMessage == false { // SessionTable[userUid].quit() // return nil, ErrorMysql //} else { SessionTable[userUid] = ClientSession go receiveMessagePacket(userUid, imDB) return ClientSession //} } //case <-time.After(time.Second * MaxDelayTime): //{ // _, flag := SessionTable[userUid] // if flag { // SessionTable[userUid].quit() // ImServerLog("Client didn't login after receiving rsa key in MaxDelayTime.") /////////////////////////////////////////////////// // } // return nil, nil //} //case caseerr := <-sqlerr: // { // if caseerr == ErrorMysql { // return nil, ErrorMysql // } // } } } return nil }
func receiveMessagePacket(uid uint64, imDB imdatabase.ImDb) { userUid := uid qfor: for { ClientSession, flag := SessionTable[userUid] if flag == false { ImServerLog("user session doesn't exist.", userUid) ///////// return } select { case pp := <-ClientSession.incoming: //提取出来的是 protobuf对象 从对象里面提取出所要的信息改session层的 name,id... { ttype := pp.GetType() //对型号为 2,4,5 进行处理。 pcmd, err := GetCommand(&pp) if err != nil { ImServerLog("GetCommand err when read type 1 packet" + err.Error()) break } random2and4p := pcmd.Message.GetRandom() dialogId := pcmd.GetReceiver() // dialogUid message := pcmd.Message.GetData() //ImPacketInTime(userUid, message, time.Now().UnixNano()) //纪录读到的包 Beat(userUid) if ttype == 1 { *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random2and4p *returnCMD.Message.Data = string(ttype) + ":had login before!" logagainreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *logagainreturnPacket break } if ttype == 5 { // 心跳包,读取name就ok } if ttype == 3 { //客户端收到信息后返回服务端4号包表示确认收到 FeedBack.DeleteOne(random2and4p) } if ttype == 2 || ttype == 4 { // 信息包或者文件包 *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random2and4p *returnCMD.Message.Data = string(ttype) + ":Server received successfully." receivesucessreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *receivesucessreturnPacket /*err := imDB.AddMessage(userUid, dialogId, pp.GetType(), message, time.Now().Format("2006-01-02 15:04:05")) if err != nil { fmt.Println("AddMessage to mysql err", err) *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = 1 *returnCMD.Message.Data = "IM Server Error!" sqlerrreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *sqlerrreturnPacket ImServerLog("IM Server Error! Because read outlinemessage err") break }*/ ImPacketInTime(userUid, message, time.Now().UnixNano()) //记录消息和在线则转发,不在线则存离线.如果dialog是活跃的才发送;转发给Dialog 里面其他所有人. //ImServerLog("Receive a message as", ttype, "User : "******". DialogId : ", dialogId) receivers, flag := ClientSession.chatMap[dialogId] if flag == true { //在chatMap里面能够找到对应的表,则发送给表内所有成员 for _, receiverUid := range receivers { sess, fl := SessionTable[receiverUid] //在线 if fl == true { //ImServerLog("Write feedback to user : "******". Server received successfully") /////////////////////////////////////// //重新制作包发给另一端 *messageCMD.Sender = dialogId *messageCMD.Receiver = receiverUid *messageCMD.Message.Data = message *messageCMD.Message.Random = GenRandom() sendPacket := MakePacket(messageCMD, ttype) sess.outgoing <- *sendPacket continue //写入数据库message表 message } //用户不在线,存离线outlinemessage *messageCMD.Sender = dialogId *messageCMD.Receiver = receiverUid *messageCMD.Message.Data = message *messageCMD.Message.Random = GenRandom() outLineMsg := MakePacket(messageCMD, ttype) err := imDB.AddOutlineMsg(receiverUid, uint32(ttype), outLineMsg.GetData(), time.Now().Format("2006-01-02 15:04:05")) if err != nil { *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = 1 *returnCMD.Message.Data = "IM Server Error!" mysqlerrreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *mysqlerrreturnPacket //ImServerLog("IM Server Error! Because read outlinemessage err") continue } //*returnCMD.Sender = 0 //*returnCMD.Receiver = userUid //*returnCMD.Message.Random = random2and4p //*returnCMD.Message.Data = string(ttype) + ":receiver isn't online!" //returnPacket := MakePacket(returnCMD, 3) //ClientSession.outgoing <- *returnPacket //ImServerLog("Write feedback to user : "******". Receiver isn't online!") ////////////////////////////////////////////////// } break } //没能在chatMap里面找到,则先扫描activedialog表,若没有则告诉客户端 if ClientSession.chatMap[dialogId] == nil { //初始化chatmap对应的切片 ClientSession.chatMap[dialogId] = make([]uint64, 0, MaxMemberInGroup) } actDialogTable, err := imDB.Db.Query("select * from act_dialog where dialog_id=? order by dialog_id", dialogId) if err != nil { *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = 1 *returnCMD.Message.Data = "IM Server Error!" queryerrreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *queryerrreturnPacket break } defer actDialogTable.Close() if actDialogTable.Next() { //这里由于数据库定好了act_dialog 的唯一性,所以存在也只会存在一次,用if足够 //查询dialog表//查询条件:dialog,时间戳为0,返回没有被踢群的用户 activeUserTable, err := imDB.Db.Query("select uid from dialog where dialog_Id=? and timestamp=?", dialogId, "0000-00-00 00:00:00") if err != nil { *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = 1 *returnCMD.Message.Data = "IM Server Error!" errorreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *errorreturnPacket break } defer activeUserTable.Close() var uid uint64 var flaguidin bool //用户在群内 for activeUserTable.Next() { err = activeUserTable.Scan(&uid) //没有被踢群的用户 if err != nil { *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = 1 *returnCMD.Message.Data = "IM Server Error!" errreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *errreturnPacket DatabaseLog("Database error in scaning dialog:" + err.Error()) break } //****************************成员加入到chatMap if uid == userUid { flaguidin = true //自己在群内,则flaguid为true continue } ClientSession.chatMap[dialogId] = append(ClientSession.chatMap[dialogId], uid) } if flaguidin != true { //自己已被踢出群 delete(ClientSession.chatMap, dialogId) //删除chatMap //这里发给用户一个命令包 type6 用户那边显示并且不能往该dialog 发送内容 *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random2and4p *returnCMD.Message.Data = string(ttype) + ":you are out of group!" outofgroupreturnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *outofgroupreturnPacket break } //自己在群内,向chatMap里的uid转发消息 for _, receiverUid := range ClientSession.chatMap[dialogId] { sess, fl := SessionTable[receiverUid] if fl == true { //重新制作包发给另一端 *messageCMD.Sender = dialogId *messageCMD.Receiver = receiverUid *messageCMD.Message.Data = message *messageCMD.Message.Random = GenRandom() sendaPacket := MakePacket(messageCMD, ttype) sess.outgoing <- *sendaPacket continue } //用户不在线,存离线outlinemessage *messageCMD.Sender = dialogId *messageCMD.Receiver = receiverUid *messageCMD.Message.Data = message *messageCMD.Message.Random = GenRandom() outLineMsg2 := MakePacket(messageCMD, ttype) err := imDB.AddOutlineMsg(receiverUid, uint32(ttype), outLineMsg2.GetData(), time.Now().Format("2006-01-02 15:04:05")) if err != nil { //fmt.Println("AddOutlinemessage to mysql err", err) *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = 1 *returnCMD.Message.Data = "IM Server Error!" returnPacket := MakePacket(returnCMD, 3) ClientSession.outgoing <- *returnPacket ImServerLog("IM Server Error! Because read outlinemessage err", err) continue } } break } //act_dialog找不到 *returnCMD.Sender = 0 *returnCMD.Receiver = userUid *returnCMD.Message.Random = random2and4p *returnCMD.Message.Data = string(ttype) + ":dialog isn't active!" returnPacket3 := MakePacket(returnCMD, 3) ClientSession.outgoing <- *returnPacket3 } _, fla := SessionTable[userUid] if fla == true { SessionTable[userUid] = ClientSession } } case <-ClientSession.quitfor: { //回馈包??? break qfor } } } }