Example #1
0
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
}
Example #2
0
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
			}
		}
	}
}