mv src/common src/utils src/grpc-etcdv3 to pkg

This commit is contained in:
xmcy0011
2021-10-11 22:12:01 +08:00
parent bc94d4e0b3
commit 737edb985b
119 changed files with 310 additions and 702 deletions
+159
View File
@@ -0,0 +1,159 @@
package config
import (
"gopkg.in/yaml.v3"
"io/ioutil"
)
var Config config
type config struct {
ServerIP string `yaml:"serverip"`
Api struct {
GinPort []int `yaml:"openImApiPort"`
}
Sdk struct {
WsPort []int `yaml:"sdkWsPort"`
}
Credential struct {
Tencent struct {
AppID string `yaml:"appID"`
Region string `yaml:"region"`
Bucket string `yaml:"bucket"`
SecretID string `yaml:"secretID"`
SecretKey string `yaml:"secretKey"`
}
}
Mysql struct {
DBAddress []string `yaml:"dbMysqlAddress"`
DBUserName string `yaml:"dbMysqlUserName"`
DBPassword string `yaml:"dbMysqlPassword"`
DBDatabaseName string `yaml:"dbMysqlDatabaseName"`
DBTableName string `yaml:"DBTableName"`
DBMsgTableNum int `yaml:"dbMsgTableNum"`
DBMaxOpenConns int `yaml:"dbMaxOpenConns"`
DBMaxIdleConns int `yaml:"dbMaxIdleConns"`
DBMaxLifeTime int `yaml:"dbMaxLifeTime"`
}
Mongo struct {
DBAddress []string `yaml:"dbAddress"`
DBDirect bool `yaml:"dbDirect"`
DBTimeout int `yaml:"dbTimeout"`
DBDatabase string `yaml:"dbDatabase"`
DBSource string `yaml:"dbSource"`
DBUserName string `yaml:"dbUserName"`
DBPassword string `yaml:"dbPassword"`
DBMaxPoolSize int `yaml:"dbMaxPoolSize"`
DBRetainChatRecords int `yaml:"dbRetainChatRecords"`
}
Redis struct {
DBAddress string `yaml:"dbAddress"`
DBMaxIdle int `yaml:"dbMaxIdle"`
DBMaxActive int `yaml:"dbMaxActive"`
DBIdleTimeout int `yaml:"dbIdleTimeout"`
DBPassWord string `yaml:"dbPassWord"`
}
RpcPort struct {
OpenImUserPort []int `yaml:"openImUserPort"`
openImFriendPort []int `yaml:"openImFriendPort"`
RpcMessagePort []int `yaml:"rpcMessagePort"`
RpcPushMessagePort []int `yaml:"rpcPushMessagePort"`
OpenImGroupPort []int `yaml:"openImGroupPort"`
RpcModifyUserInfoPort []int `yaml:"rpcModifyUserInfoPort"`
RpcGetTokenPort []int `yaml:"rpcGetTokenPort"`
}
RpcRegisterName struct {
OpenImUserName string `yaml:"openImUserName"`
OpenImFriendName string `yaml:"openImFriendName"`
OpenImOfflineMessageName string `yaml:"openImOfflineMessageName"`
OpenImPushName string `yaml:"openImPushName"`
OpenImOnlineMessageRelayName string `yaml:"openImOnlineMessageRelayName"`
OpenImGroupName string `yaml:"openImGroupName"`
RpcGetTokenName string `yaml:"rpcGetTokenName"`
}
Etcd struct {
EtcdSchema string `yaml:"etcdSchema"`
EtcdAddr []string `yaml:"etcdAddr"`
}
Log struct {
StorageLocation string `yaml:"storageLocation"`
RotationTime int `yaml:"rotationTime"`
RemainRotationCount uint `yaml:"remainRotationCount"`
ElasticSearchSwitch bool `yaml:"elasticSearchSwitch"`
ElasticSearchAddr []string `yaml:"elasticSearchAddr"`
ElasticSearchUser string `yaml:"elasticSearchUser"`
ElasticSearchPassword string `yaml:"elasticSearchPassword"`
}
ModuleName struct {
LongConnSvrName string `yaml:"longConnSvrName"`
MsgTransferName string `yaml:"msgTransferName"`
PushName string `yaml:"pushName"`
}
LongConnSvr struct {
WebsocketPort []int `yaml:"websocketPort"`
WebsocketMaxConnNum int `yaml:"websocketMaxConnNum"`
WebsocketMaxMsgLen int `yaml:"websocketMaxMsgLen"`
WebsocketTimeOut int `yaml:"websocketTimeOut"`
}
Push struct {
Tpns struct {
Ios struct {
AccessID string `yaml:"accessID"`
SecretKey string `yaml:"secretKey"`
}
Android struct {
AccessID string `yaml:"accessID"`
SecretKey string `yaml:"secretKey"`
}
}
}
Manager struct {
AppManagerUid []string `yaml:"appManagerUid"`
Secrets []string `yaml:"secrets"`
}
Kafka struct {
Ws2mschat struct {
Addr []string `yaml:"addr"`
Topic string `yaml:"topic"`
}
Ms2pschat struct {
Addr []string `yaml:"addr"`
Topic string `yaml:"topic"`
}
ConsumerGroupID struct {
MsgToMongo string `yaml:"msgToMongo"`
MsgToMySql string `yaml:"msgToMySql"`
MsgToPush string `yaml:"msgToPush"`
}
}
Secret string `yaml:"secret"`
MultiLoginPolicy struct {
OnlyOneTerminalAccess bool `yaml:"onlyOneTerminalAccess"`
MobileAndPCTerminalAccessButOtherTerminalKickEachOther bool `yaml:"mobileAndPCTerminalAccessButOtherTerminalKickEachOther"`
AllTerminalAccess bool `yaml:"allTerminalAccess"`
}
TokenPolicy struct {
AccessSecret string `yaml:"accessSecret"`
AccessExpire int64 `yaml:"accessExpire"`
}
MessageCallBack struct {
CallbackSwitch bool `yaml:"callbackSwitch"`
CallbackUrl string `yaml:"callbackUrl"`
}
}
func init() {
bytes, err := ioutil.ReadFile("config/config.yaml")
if err != nil {
panic(err)
return
}
if err = yaml.Unmarshal(bytes, &Config); err != nil {
panic(err)
return
}
}
+48
View File
@@ -0,0 +1,48 @@
package config
// key = errCode, string = errMsg
type ErrInfo struct {
ErrCode int32
ErrMsg string
}
var (
OK = ErrInfo{0, ""}
ErrMysql = ErrInfo{100, ""}
ErrMongo = ErrInfo{110, ""}
ErrRedis = ErrInfo{120, ""}
ErrParseToken = ErrInfo{200, "Parse token failed"}
ErrCreateToken = ErrInfo{201, "Create token failed"}
ErrAppServerKey = ErrInfo{300, "key error"}
ErrTencentCredential = ErrInfo{400, ""}
ErrorUserRegister = ErrInfo{600, "User registration failed"}
ErrAccountExists = ErrInfo{601, "The account is already registered and cannot be registered again"}
ErrUserPassword = ErrInfo{602, "User password error"}
ErrTokenIncorrect = ErrInfo{603, "Invalid token"}
ErrTokenExpired = ErrInfo{604, "Expired token"}
ErrRefreshToken = ErrInfo{605, "Failed to refresh token"}
ErrAddFriend = ErrInfo{606, "Failed to add friends"}
ErrAgreeToAddFriend = ErrInfo{607, "Failed to agree application"}
ErrAddFriendToBlack = ErrInfo{608, "Failed to add friends to the blacklist"}
ErrGetBlackList = ErrInfo{609, "Failed to get blacklist"}
ErrDeleteFriend = ErrInfo{610, "Failed to delete friend"}
ErrGetFriendApplyList = ErrInfo{611, "Failed to get friend application list"}
ErrGetFriendList = ErrInfo{612, "Failed to get friend list"}
ErrRemoveBlackList = ErrInfo{613, "Failed to remove blacklist"}
ErrSearchUserInfo = ErrInfo{614, "Can't find the user information"}
ErrDelAppleDeviceToken = ErrInfo{615, ""}
ErrModifyUserInfo = ErrInfo{616, "update user some attribute failed"}
ErrSetFriendComment = ErrInfo{617, "set friend comment failed"}
ErrSearchUserInfoFromTheGroup = ErrInfo{618, "There is no such group or the user not in the group"}
ErrCreateGroup = ErrInfo{619, "create group chat failed"}
ErrJoinGroupApplication = ErrInfo{620, "Failed to apply to join the group"}
ErrQuitGroup = ErrInfo{621, "Failed to quit the group"}
ErrSetGroupInfo = ErrInfo{622, "Failed to set group info"}
ErrParam = ErrInfo{ErrCode: 700, ErrMsg: "param failed"}
ErrAccess = ErrInfo{ErrCode: 800, ErrMsg: "no permission"}
ErrDb = ErrInfo{ErrCode: 900, ErrMsg: "db failed"}
)
+73
View File
@@ -0,0 +1,73 @@
package constant
const (
//group admin
OrdinaryMember = 0
GroupOwner = 1
Administrator = 2
//group application
Application = 0
AgreeApplication = 1
//feiend related
BlackListFlag = 1
ApplicationFriendFlag = 0
FriendFlag = 1
RefuseFriendFlag = -1
//Websocket Protocol
WSGetNewestSeq = 1001
WSPullMsg = 1002
WSSendMsg = 1003
WSPushMsg = 2001
///ContentType
//UserRelated
Text = 101
Picture = 102
Voice = 103
Video = 104
File = 105
AtText = 106
Custom = 110
SyncSenderMsg = 108
//SysRelated
AcceptFriendApplicationTip = 201
AddFriendTip = 202
RefuseFriendApplicationTip = 203
SetSelfInfoTip = 204
Revoke = 205
C2CMessageAsRead = 206
KickOnlineTip = 303
TransferGroupOwnerTip = 501
CreateGroupTip = 502
GroupApplicationResponseTip = 503
JoinGroupTip = 504
QuitGroupTip = 505
SetGroupInfoTip = 506
AcceptGroupApplicationTip = 507
RefuseGroupApplicationTip = 508
KickGroupMemberTip = 509
InviteUserToGroupTip = 510
//MsgFrom
UserMsgType = 100
SysMsgType = 200
//SessionType
SingleChatType = 1
GroupChatType = 2
)
var ContentType2PushContent = map[int64]string{
Picture: "[picture]",
Voice: "[voice]",
Video: "[video]",
File: "[file]",
}
const FriendAcceptTip = "You have successfully become friends, so start chatting"
+60
View File
@@ -0,0 +1,60 @@
package db
import (
"Open_IM/pkg/common/config"
"github.com/garyburd/redigo/redis"
"gopkg.in/mgo.v2"
"time"
)
var DB DataBases
type DataBases struct {
MysqlDB mysqlDB
mgoSession *mgo.Session
redisPool *redis.Pool
}
func key(dbAddress, dbName string) string {
return dbAddress + "_" + dbName
}
func init() {
//mysql init
initMysqlDB()
// mongo init
mgoDailInfo := &mgo.DialInfo{
Addrs: config.Config.Mongo.DBAddress,
Direct: config.Config.Mongo.DBDirect,
Timeout: time.Second * time.Duration(config.Config.Mongo.DBTimeout),
Database: config.Config.Mongo.DBDatabase,
Source: config.Config.Mongo.DBSource,
Username: config.Config.Mongo.DBUserName,
Password: config.Config.Mongo.DBPassword,
PoolLimit: config.Config.Mongo.DBMaxPoolSize,
}
mgoSession, err := mgo.DialWithInfo(mgoDailInfo)
if err != nil {
panic(err)
}
DB.mgoSession = mgoSession
DB.mgoSession.SetMode(mgo.Monotonic, true)
// redis pool init
DB.redisPool = &redis.Pool{
MaxIdle: config.Config.Redis.DBMaxIdle,
MaxActive: config.Config.Redis.DBMaxActive,
IdleTimeout: time.Duration(config.Config.Redis.DBIdleTimeout) * time.Second,
Dial: func() (redis.Conn, error) {
return redis.Dial(
"tcp",
config.Config.Redis.DBAddress,
redis.DialReadTimeout(time.Duration(1000)*time.Millisecond),
redis.DialWriteTimeout(time.Duration(1000)*time.Millisecond),
redis.DialConnectTimeout(time.Duration(1000)*time.Millisecond),
redis.DialDatabase(0),
redis.DialPassword(config.Config.Redis.DBPassWord),
)
},
}
}
+233
View File
@@ -0,0 +1,233 @@
package db
import (
pbMsg "Open_IM/pkg/proto/chat"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"errors"
"github.com/golang/protobuf/proto"
"gopkg.in/mgo.v2/bson"
"time"
)
const cChat = "chat"
const cGroup = "group"
type MsgInfo struct {
SendTime int64
Msg []byte
}
type UserChat struct {
UID string
Msg []MsgInfo
}
type GroupMember struct {
GroupID string
UIDList []string
}
func (d *DataBases) GetUserChat(uid string, seqBegin, seqEnd int64) (SingleMsg []*pbMsg.MsgFormat, GroupMsg []*pbMsg.MsgFormat, MaxSeq int64, MinSeq int64, err error) {
count := 0
session := d.mgoSession.Clone()
if session == nil {
return nil, nil, MaxSeq, MinSeq, errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
sChat := UserChat{}
if err = c.Find(bson.M{"uid": uid}).One(&sChat); err != nil {
return nil, nil, MaxSeq, MinSeq, err
}
pChat := pbMsg.MsgSvrToPushSvrChatMsg{}
for i := 0; i < len(sChat.Msg); i++ {
temp := new(pbMsg.MsgFormat)
if err = proto.Unmarshal(sChat.Msg[i].Msg, &pChat); err != nil {
return nil, nil, MaxSeq, MinSeq, err
}
if pChat.RecvSeq >= seqBegin && pChat.RecvSeq <= seqEnd {
temp.SendID = pChat.SendID
temp.RecvID = pChat.RecvID
temp.MsgFrom = pChat.MsgFrom
temp.Seq = pChat.RecvSeq
temp.ServerMsgID = pChat.MsgID
temp.SendTime = pChat.SendTime
temp.Content = pChat.Content
temp.ContentType = pChat.ContentType
temp.SenderPlatformID = pChat.PlatformID
temp.ClientMsgID = pChat.ClientMsgID
temp.SenderFaceURL = pChat.SenderFaceURL
temp.SenderNickName = pChat.SenderNickName
if pChat.RecvSeq > MaxSeq {
MaxSeq = pChat.RecvSeq
}
if count == 0 {
MinSeq = pChat.RecvSeq
}
if pChat.RecvSeq < MinSeq {
MinSeq = pChat.RecvSeq
}
if pChat.SessionType == constant.SingleChatType {
SingleMsg = append(SingleMsg, temp)
} else {
GroupMsg = append(GroupMsg, temp)
}
count++
}
}
return SingleMsg, GroupMsg, MaxSeq, MinSeq, nil
}
func (d *DataBases) SaveUserChat(uid string, sendTime int64, m proto.Message) error {
session := d.mgoSession.Clone()
if session == nil {
return errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
n, err := c.Find(bson.M{"uid": uid}).Count()
if err != nil {
return err
}
sMsg := MsgInfo{}
sMsg.SendTime = sendTime
if sMsg.Msg, err = proto.Marshal(m); err != nil {
return err
}
if n == 0 {
sChat := UserChat{}
sChat.UID = uid
sChat.Msg = append(sChat.Msg, sMsg)
err = c.Insert(&sChat)
if err != nil {
return err
}
} else {
err = c.Update(bson.M{"uid": uid}, bson.M{"$push": bson.M{"msg": sMsg}})
if err != nil {
return err
}
}
return nil
}
func (d *DataBases) DelUserChat(uid string) error {
session := d.mgoSession.Clone()
if session == nil {
return errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
delTime := time.Now().Unix() - int64(config.Config.Mongo.DBRetainChatRecords)*24*3600
if err := c.Update(bson.M{"uid": uid}, bson.M{"$pull": bson.M{"msg": bson.M{"sendtime": bson.M{"$lte": delTime}}}}); err != nil {
return err
}
return nil
}
func (d *DataBases) MgoUserCount() (int, error) {
session := d.mgoSession.Clone()
if session == nil {
return 0, errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
return c.Find(nil).Count()
}
func (d *DataBases) MgoSkipUID(count int) (string, error) {
session := d.mgoSession.Clone()
if session == nil {
return "", errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cChat)
sChat := UserChat{}
c.Find(nil).Skip(count).Limit(1).One(&sChat)
return sChat.UID, nil
}
func (d *DataBases) GetGroupMember(groupID string) []string {
groupInfo := GroupMember{}
groupInfo.GroupID = groupID
groupInfo.UIDList = make([]string, 0)
session := d.mgoSession.Clone()
if session == nil {
return groupInfo.UIDList
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup)
if err := c.Find(bson.M{"groupid": groupInfo.GroupID}).One(&groupInfo); err != nil {
return groupInfo.UIDList
}
return groupInfo.UIDList
}
func (d *DataBases) AddGroupMember(groupID, uid string) error {
session := d.mgoSession.Clone()
if session == nil {
return errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup)
n, err := c.Find(bson.M{"groupid": groupID}).Count()
if err != nil {
return err
}
if n == 0 {
groupInfo := GroupMember{}
groupInfo.GroupID = groupID
groupInfo.UIDList = append(groupInfo.UIDList, uid)
err = c.Insert(&groupInfo)
if err != nil {
return err
}
} else {
err = c.Update(bson.M{"groupid": groupID}, bson.M{"$addToSet": bson.M{"uidlist": uid}})
if err != nil {
return err
}
}
return nil
}
func (d *DataBases) DelGroupMember(groupID, uid string) error {
session := d.mgoSession.Clone()
if session == nil {
return errors.New("session == nil")
}
defer session.Close()
c := session.DB(config.Config.Mongo.DBDatabase).C(cGroup)
if err := c.Update(bson.M{"groupid": groupID}, bson.M{"$pull": bson.M{"uidlist": uid}}); err != nil {
return err
}
return nil
}
+136
View File
@@ -0,0 +1,136 @@
package db
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/log"
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
"sync"
"time"
)
type mysqlDB struct {
sync.RWMutex
dbMap map[string]*gorm.DB
}
func initMysqlDB() {
//When there is no open IM database, connect to the mysql built-in database to create openIM database
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], "mysql")
db, err := gorm.Open("mysql", dsn)
if err != nil {
log.Error("", "", dsn)
panic(err)
}
//Check the database and table during initialization
sql := fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s ;", config.Config.Mysql.DBDatabaseName)
err = db.Exec(sql).Error
if err != nil {
panic(err)
}
db.Close()
dsn = fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, config.Config.Mysql.DBAddress[0], config.Config.Mysql.DBDatabaseName)
db, err = gorm.Open("mysql", dsn)
if err != nil {
panic(err)
}
sqlTable := "CREATE TABLE IF NOT EXISTS `user` (\n `uid` varchar(64) NOT NULL,\n `name` varchar(64) DEFAULT NULL,\n `icon` varchar(1024) DEFAULT NULL,\n `gender` int(11) unsigned zerofill DEFAULT NULL,\n `mobile` varchar(32) DEFAULT NULL,\n `birth` varchar(16) DEFAULT NULL,\n `email` varchar(64) DEFAULT NULL,\n `ex` varchar(1024) DEFAULT NULL,\n `create_time` datetime DEFAULT NULL,\n PRIMARY KEY (`uid`),\n UNIQUE KEY `uk_uid` (`uid`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `friend` (\n `owner_id` varchar(255) NOT NULL,\n `friend_id` varchar(255) NOT NULL,\n `comment` varchar(255) DEFAULT NULL,\n `friend_flag` int(11) NOT NULL,\n `create_time` datetime NOT NULL,\n PRIMARY KEY (`owner_id`,`friend_id`) USING BTREE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `friend_request` (\n `req_id` varchar(255) NOT NULL,\n `user_id` varchar(255) NOT NULL,\n `flag` int(11) NOT NULL DEFAULT '0',\n `req_message` varchar(255) DEFAULT NULL,\n `create_time` datetime NOT NULL,\n PRIMARY KEY (`user_id`,`req_id`) USING BTREE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `black_list` (\n `uid` varchar(32) NOT NULL COMMENT 'uid',\n `begin_disable_time` datetime DEFAULT NULL,\n `end_disable_time` datetime DEFAULT NULL,\n `ex` varchar(1024) DEFAULT NULL,\n PRIMARY KEY (`uid`) USING BTREE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `user_black_list` (\n `owner_id` varchar(255) NOT NULL,\n `block_id` varchar(255) NOT NULL,\n `create_time` datetime NOT NULL,\n PRIMARY KEY (`owner_id`,`block_id`) USING BTREE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `group` (\n `group_id` varchar(255) NOT NULL,\n `name` varchar(255) DEFAULT NULL,\n `introduction` varchar(255) DEFAULT NULL,\n `notification` varchar(255) DEFAULT NULL,\n `face_url` varchar(255) DEFAULT NULL,\n `create_time` datetime DEFAULT NULL,\n `ex` varchar(255) DEFAULT NULL,\n PRIMARY KEY (`group_id`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `group_member` (\n `group_id` varchar(255) NOT NULL,\n `uid` varchar(255) NOT NULL,\n `nickname` varchar(255) DEFAULT NULL,\n `user_group_face_url` varchar(255) DEFAULT NULL,\n `administrator_level` int(11) NOT NULL,\n `join_time` datetime NOT NULL,\n PRIMARY KEY (`group_id`,`uid`) USING BTREE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `group_request` (\n `id` int(11) NOT NULL AUTO_INCREMENT,\n `group_id` varchar(255) NOT NULL,\n `from_user_id` varchar(255) NOT NULL,\n `to_user_id` varchar(255) NOT NULL,\n `flag` int(10) NOT NULL DEFAULT '0',\n `req_msg` varchar(255) DEFAULT '',\n `handled_msg` varchar(255) DEFAULT '',\n `create_time` datetime NOT NULL,\n `from_user_nickname` varchar(255) DEFAULT '',\n `to_user_nickname` varchar(255) DEFAULT NULL,\n `from_user_face_url` varchar(255) DEFAULT '',\n `to_user_face_url` varchar(255) DEFAULT '',\n `handled_user` varchar(255) DEFAULT '',\n PRIMARY KEY (`id`)\n) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8mb4;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
sqlTable = "CREATE TABLE IF NOT EXISTS `chat_log` (\n `msg_id` varchar(128) NOT NULL,\n `send_id` varchar(255) NOT NULL,\n `session_type` int(11) NOT NULL,\n `recv_id` varchar(255) NOT NULL,\n `content_type` int(11) NOT NULL,\n `msg_from` int(11) NOT NULL,\n `content` varchar(1000) NOT NULL,\n `remark` varchar(100) DEFAULT NULL,\n `sender_platform_id` int(11) NOT NULL,\n `send_time` datetime NOT NULL,\n PRIMARY KEY (`msg_id`) USING BTREE\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"
err = db.Exec(sqlTable).Error
if err != nil {
panic(err)
}
}
func (m *mysqlDB) DefaultGormDB() (*gorm.DB, error) {
return m.GormDB(config.Config.Mysql.DBAddress[0], config.Config.Mysql.DBDatabaseName)
}
func (m *mysqlDB) GormDB(dbAddress, dbName string) (*gorm.DB, error) {
m.Lock()
defer m.Unlock()
k := key(dbAddress, dbName)
if _, ok := m.dbMap[k]; !ok {
if err := m.open(dbAddress, dbName); err != nil {
return nil, err
}
}
return m.dbMap[k], nil
}
func (m *mysqlDB) open(dbAddress, dbName string) error {
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local",
config.Config.Mysql.DBUserName, config.Config.Mysql.DBPassword, dbAddress, dbName)
db, err := gorm.Open("mysql", dsn)
if err != nil {
return err
}
db.SingularTable(true)
db.DB().SetMaxOpenConns(config.Config.Mysql.DBMaxOpenConns)
db.DB().SetMaxIdleConns(config.Config.Mysql.DBMaxIdleConns)
db.DB().SetConnMaxLifetime(time.Duration(config.Config.Mysql.DBMaxLifeTime) * time.Second)
if m.dbMap == nil {
m.dbMap = make(map[string]*gorm.DB)
}
k := key(dbAddress, dbName)
m.dbMap[k] = db
return nil
}
@@ -0,0 +1,69 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
_ "github.com/jinzhu/gorm/dialects/mysql"
"time"
)
func InsertToFriend(ownerId, friendId string, flag int32) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
toInsertFollow := Friend{
OwnerId: ownerId,
FriendId: friendId,
FriendFlag: flag,
CreateTime: time.Now(),
}
err = dbConn.Table("friend").Create(toInsertFollow).Error
if err != nil {
return err
}
return nil
}
func FindFriendRelationshipFromFriend(ownerId, friendId string) (*Friend, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var friend Friend
err = dbConn.Table("friend").Where("owner_id=? and friend_id=?", ownerId, friendId).Find(&friend).Error
if err != nil {
return nil, err
}
return &friend, err
}
func FindUserInfoFromFriend(ownerId string) ([]Friend, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var friends []Friend
err = dbConn.Table("friend").Where("owner_id=?", ownerId).Find(&friends).Error
if err != nil {
return nil, err
}
return friends, nil
}
func UpdateFriendComment(ownerId, friendId, comment string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("update friend set comment=? where owner_id=? and friend_id=?", comment, ownerId, friendId).Error
return err
}
func DeleteSingleFriendInfo(ownerId, friendId string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Table("friend").Where("owner_id=? and friend_id=?", ownerId, friendId).Delete(Friend{}).Error
return err
}
@@ -0,0 +1,70 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
"time"
)
func ReplaceIntoFriendReq(reqId, userId string, flag int32, reqMessage string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("replace into friend_request(req_id,user_id,flag,req_message,create_time) values(?,?,?,?,?)", reqId, userId, flag, reqMessage, time.Now()).Error
if err != nil {
return err
}
return nil
}
func FindFriendsApplyFromFriendReq(userId string) ([]FriendRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var usersInfo []FriendRequest
//dbConn.LogMode(true)
err = dbConn.Table("friend_request").Where("user_id=?", userId).Find(&usersInfo).Error
if err != nil {
return nil, err
}
return usersInfo, nil
}
func FindSelfApplyFromFriendReq(userId string) ([]FriendRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var usersInfo []FriendRequest
err = dbConn.Table("friend_request").Where("req_id=?", userId).Find(&usersInfo).Error
if err != nil {
return nil, err
}
return usersInfo, nil
}
func FindFriendApplyFromFriendReqByUid(reqId, userId string) (*FriendRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var friendRequest FriendRequest
err = dbConn.Table("friend_request").Where("req_id=? and user_id=?", reqId, userId).Find(&friendRequest).Error
if err != nil {
return nil, err
}
return &friendRequest, nil
}
func UpdateFriendRelationshipToFriendReq(reqId, userId string, flag int32) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("update friend_request set flag=? where req_id=? and user_id=?", flag, reqId, userId).Error
if err != nil {
return err
}
return nil
}
@@ -0,0 +1,217 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
"time"
)
func InsertIntoGroupMember(groupId, uid, nickName, userGroupFaceUrl string, administratorLevel int32) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
toInsertInfo := GroupMember{GroupId: groupId, Uid: uid, NickName: nickName, AdministratorLevel: administratorLevel, JoinTime: time.Now(), UserGroupFaceUrl: userGroupFaceUrl}
err = dbConn.Table("group_member").Create(toInsertInfo).Error
if err != nil {
return err
}
return nil
}
func FindGroupMemberListByUserId(uid string) ([]GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMemberList []GroupMember
err = dbConn.Raw("select * from `group_member` where uid=?", uid).Find(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func FindGroupMemberListByGroupId(groupId string) ([]GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMemberList []GroupMember
err = dbConn.Raw("select * from `group_member` where group_id=?", groupId).Find(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func FindGroupMemberListByGroupIdAndFilterInfo(groupId string, filter int32) ([]GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
dbConn.LogMode(true)
if err != nil {
return nil, err
}
var groupMemberList []GroupMember
err = dbConn.Raw("select * from `group_member` where group_id=? and administrator_level=?", groupId, filter).Find(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func FindGroupMemberInfoByGroupIdAndUserId(groupId, uid string) (*GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMember GroupMember
err = dbConn.Raw("select * from `group_member` where group_id=? and uid=? limit 1", groupId, uid).Scan(&groupMember).Error
if err != nil {
return nil, err
}
return &groupMember, nil
}
func DeleteGroupMemberByGroupIdAndUserId(groupId, uid string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("delete from `group_member` where group_id=? and uid=?", groupId, uid).Error
if err != nil {
return err
}
return nil
}
func UpdateOwnerGroupNickName(groupId, userId, groupNickName string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("update `group_member` set nickname=? where group_id=? and uid=?", groupNickName, groupId, userId).Error
if err != nil {
return err
}
return nil
}
func SelectGroupList(groupID string) ([]string, error) {
var groupUserID string
var groupList []string
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return groupList, err
}
rows, err := dbConn.Model(&GroupMember{}).Where("group_id = ?", groupID).Select("user_id").Rows()
if err != nil {
return groupList, err
}
defer rows.Close()
for rows.Next() {
rows.Scan(&groupUserID)
groupList = append(groupList, groupUserID)
}
return groupList, nil
}
func UpdateTheUserAdministratorLevel(groupId, uid string, administratorLevel int64) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("update `group_member` set administrator_level=? where group_id=? and uid=?", administratorLevel, groupId, uid).Error
if err != nil {
return err
}
return nil
}
func GetOwnerManagerByGroupId(groupId string) ([]GroupMember, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupMemberList []GroupMember
err = dbConn.Raw("select * from `group_member` where group_id=? and administrator_level > 0", groupId).Find(&groupMemberList).Error
if err != nil {
return nil, err
}
return groupMemberList, nil
}
func IsExistGroupMember(groupId, uid string) bool {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return false
}
var number int32
err = dbConn.Raw("select count(*) from `group_member` where group_id = ? and uid = ?", groupId, uid).Count(&number).Error
if err != nil {
return false
}
if number != 1 {
return false
}
return true
}
func RemoveGroupMember(groupId string, memberId string) error {
return DeleteGroupMemberByGroupIdAndUserId(groupId, memberId)
}
func GetMemberInfoById(groupId string, memberId string) (*GroupMember, error) {
return FindGroupMemberInfoByGroupIdAndUserId(groupId, memberId)
}
func GetGroupMemberByGroupId(groupId string, filter int32, begin int32, maxNumber int32) ([]GroupMember, error) {
memberList, err := FindGroupMemberListByGroupId(groupId) //sorted by join time
if err != nil {
return nil, err
}
if begin >= int32(len(memberList)) {
return nil, nil
}
var end int32
if begin+int32(maxNumber) < int32(len(memberList)) {
end = begin + maxNumber
} else {
end = int32(len(memberList))
}
return memberList[begin:end], nil
}
func GetJoinedGroupIdListByMemberId(memberId string) ([]GroupMember, error) {
return FindGroupMemberListByUserId(memberId)
}
func GetGroupMemberNumByGroupId(groupId string) int32 {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return 0
}
var number int32
err = dbConn.Raw("select count(*) from `group_member` where group_id=? ", groupId).Count(&number).Error
if err != nil {
return 0
}
return number
}
func GetGroupOwnerByGroupId(groupId string) string {
omList, err := GetOwnerManagerByGroupId(groupId)
if err != nil {
return ""
}
for _, v := range omList {
if v.AdministratorLevel == 1 {
return v.Uid
}
}
return ""
}
func InsertGroupMember(groupId, userId, nickName, userFaceUrl string, role int32) error {
return InsertIntoGroupMember(groupId, userId, nickName, userFaceUrl, role)
}
@@ -0,0 +1,302 @@
package im_mysql_model
import (
"Open_IM/pkg/proto/group"
"Open_IM/pkg/common/db"
"Open_IM/pkg/common/log"
"errors"
"time"
)
func InsertIntoGroup(groupId, name, introduction, notification, faceUrl, ex string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
//Default group name
if name == "" {
name = "groupChat"
}
toInsertInfo := Group{GroupId: groupId, Name: name, Introduction: introduction, Notification: notification, FaceUrl: faceUrl, CreateTime: time.Now(), Ex: ex}
err = dbConn.Table("group").Create(toInsertInfo).Error
if err != nil {
return err
}
return nil
}
func FindGroupInfoByGroupId(groupId string) (*Group, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupInfo Group
err = dbConn.Raw("select * from `group` where group_id=?", groupId).Scan(&groupInfo).Error
if err != nil {
return nil, err
}
return &groupInfo, nil
}
func SetGroupInfo(groupId, groupName, introduction, notification, groupFaceUrl, ex string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
dbConn.LogMode(true)
if err != nil {
return err
}
if groupName != "" {
if err = dbConn.Exec("update `group` set name=? where group_id=?", groupName, groupId).Error; err != nil {
return err
}
}
if introduction != "" {
if err = dbConn.Exec("update `group` set introduction=? where group_id=?", introduction, groupId).Error; err != nil {
return err
}
}
if notification != "" {
if err = dbConn.Exec("update `group` set notification=? where group_id=?", notification, groupId).Error; err != nil {
return err
}
}
if groupFaceUrl != "" {
if err = dbConn.Exec("update `group` set face_url=? where group_id=?", groupFaceUrl, groupId).Error; err != nil {
return err
}
}
if ex != "" {
if err = dbConn.Exec("update `group` set ex=? where group_id=?", ex, groupId).Error; err != nil {
return err
}
}
return nil
}
func GetGroupApplicationList(uid string) (*group.GetGroupApplicationListResp, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var gID string
var gIDs []string
rows, err := dbConn.Raw("select group_id from `group_member` where uid = ? and administrator_level > 0", uid).Rows()
defer rows.Close()
if err != nil {
return nil, err
}
for rows.Next() {
rows.Scan(&gID)
gIDs = append(gIDs, gID)
}
if len(gIDs) == 0 {
return &group.GetGroupApplicationListResp{}, nil
}
sql := "select id, group_id, from_user_id, to_user_id, flag, req_msg, handled_msg, create_time, " +
"from_user_nickname, to_user_nickname, from_user_face_url, to_user_face_url, handled_user from `group_request` where group_id in ( "
for i := 0; i < len(gIDs); i++ {
if i == len(gIDs)-1 {
sql = sql + "\"" + gIDs[i] + "\"" + " )"
} else {
sql = sql + "\"" + gIDs[i] + "\"" + ", "
}
}
var groupRequest GroupRequest
var groupRequests []GroupRequest
log.Info("", "", sql)
rows, err = dbConn.Raw(sql).Rows()
defer rows.Close()
if err != nil {
return nil, err
}
for rows.Next() {
rows.Scan(&groupRequest.ID, &groupRequest.GroupID, &groupRequest.FromUserID, &groupRequest.ToUserID, &groupRequest.Flag, &groupRequest.ReqMsg,
&groupRequest.HandledMsg, &groupRequest.CreateTime, &groupRequest.FromUserNickname, &groupRequest.ToUserNickname,
&groupRequest.FromUserFaceUrl, &groupRequest.ToUserFaceUrl, &groupRequest.HandledUser)
groupRequests = append(groupRequests, groupRequest)
}
reply := &group.GetGroupApplicationListResp{}
reply.Data = &group.GetGroupApplicationListData{}
reply.Data.Count = int32(len(groupRequests))
for i := 0; i < int(reply.Data.Count); i++ {
addUser := group.GetGroupApplicationList_Data_User{
ID: groupRequests[i].ID,
GroupID: groupRequests[i].GroupID,
FromUserID: groupRequests[i].FromUserID,
FromUserNickname: groupRequests[i].FromUserNickname,
FromUserFaceUrl: groupRequests[i].FromUserFaceUrl,
ToUserID: groupRequests[i].ToUserID,
AddTime: groupRequests[i].CreateTime.Unix(),
RequestMsg: groupRequests[i].ReqMsg,
HandledMsg: groupRequests[i].HandledMsg,
Flag: groupRequests[i].Flag,
ToUserNickname: groupRequests[i].ToUserNickname,
ToUserFaceUrl: groupRequests[i].ToUserFaceUrl,
HandledUser: groupRequests[i].HandledUser,
Type: 0,
HandleStatus: 0,
HandleResult: 0,
}
if addUser.ToUserID != "0" {
addUser.Type = 1
}
if len(groupRequests[i].HandledUser) > 0 {
if groupRequests[i].HandledUser == uid {
addUser.HandleStatus = 2
} else {
addUser.HandleStatus = 1
}
}
if groupRequests[i].Flag == 1 {
addUser.HandleResult = 1
}
reply.Data.User = append(reply.Data.User, &addUser)
}
return reply, nil
}
func TransferGroupOwner(pb *group.TransferGroupOwnerReq) (*group.TransferGroupOwnerResp, error) {
oldOwner, err := FindGroupMemberInfoByGroupIdAndUserId(pb.GroupID, pb.OldOwner)
if err != nil {
return nil, err
}
newOwner, err := FindGroupMemberInfoByGroupIdAndUserId(pb.GroupID, pb.NewOwner)
if err != nil {
return nil, err
}
if oldOwner.Uid == newOwner.Uid {
return nil, errors.New("the self")
}
if err = UpdateTheUserAdministratorLevel(pb.GroupID, pb.OldOwner, 0); err != nil {
return nil, err
}
if err = UpdateTheUserAdministratorLevel(pb.GroupID, pb.NewOwner, 1); err != nil {
UpdateTheUserAdministratorLevel(pb.GroupID, pb.OldOwner, 1)
return nil, err
}
return &group.TransferGroupOwnerResp{}, nil
}
func GroupApplicationResponse(pb *group.GroupApplicationResponseReq) (*group.GroupApplicationResponseResp, error) {
ownerUser, err := FindGroupMemberInfoByGroupIdAndUserId(pb.GroupID, pb.OwnerID)
if err != nil {
log.ErrorByKv("FindGroupMemberInfoByGroupIdAndUserId failed", pb.OperationID, "groupId", pb.GroupID, "ownerID", pb.OwnerID)
return nil, err
}
if ownerUser.AdministratorLevel <= 0 {
return nil, errors.New("insufficient permissions")
}
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var groupRequest GroupRequest
err = dbConn.Raw("select * from `group_request` where handled_user = ? and group_id = ? and from_user_id = ? and to_user_id = ?",
"", pb.GroupID, pb.FromUserID, pb.ToUserID).Scan(&groupRequest).Error
if err != nil {
log.ErrorByKv("find group_request info failed", pb.OperationID, "groupId", pb.GroupID, "fromUserId", pb.FromUserID, "toUserId", pb.OwnerID)
return nil, err
}
if groupRequest.Flag != 0 {
return nil, errors.New("application has already handle")
}
var saveFlag int
if pb.HandleResult == 0 {
saveFlag = -1
} else if pb.HandleResult == 1 {
saveFlag = 1
} else {
return nil, errors.New("parma HandleResult error")
}
err = dbConn.Exec("update `group_request` set flag = ?, handled_msg = ?, handled_user = ? where group_id = ? and from_user_id = ? and to_user_id = ?",
saveFlag, pb.HandledMsg, pb.OwnerID, groupRequest.GroupID, groupRequest.FromUserID, groupRequest.ToUserID).Error
if err != nil {
log.ErrorByKv("update group request failed", pb.OperationID, "groupID", pb.GroupID, "flag", saveFlag, "ownerId", pb.OwnerID, "fromUserId", pb.FromUserID, "toUserID", pb.ToUserID)
return nil, err
}
if saveFlag == 1 {
if groupRequest.ToUserID == "0" {
err = InsertIntoGroupMember(pb.GroupID, pb.FromUserID, groupRequest.FromUserNickname, groupRequest.FromUserFaceUrl, 0)
if err != nil {
log.ErrorByKv("InsertIntoGroupMember failed", pb.OperationID, "groupID", pb.GroupID, "fromUserId", pb.FromUserID)
return nil, err
}
} else {
err = InsertIntoGroupMember(pb.GroupID, pb.ToUserID, groupRequest.ToUserNickname, groupRequest.ToUserFaceUrl, 0)
if err != nil {
log.ErrorByKv("InsertIntoGroupMember failed", pb.OperationID, "groupID", pb.GroupID, "fromUserId", pb.FromUserID)
return nil, err
}
}
}
//if err != nil {
// err = dbConn.Raw("select * from `group_request` where handled_user = ? and group_id = ? and to_user_id = ? and from_user_id = ?", "", pb.GroupID, "0", pb.UID).Scan(&groupRequest).Error
// if err != nil {
// return nil, err
// }
// if pb.Flag == 1 {
// err = dbConn.Exec("update `group_request` set flag = ?, handled_msg = ?, handled_user = ? where group_id = ? and to_user_id = ? and from_user_id = ?",
// pb.Flag, pb.RespMsg, pb.OwnerID, pb.GroupID, "0", pb.UID).Error
// if err != nil {
// return nil, err
// }
//
// // add to group member
// err = InsertIntoGroupMember(pb.GroupID, pb.UID, groupRequest.FromUserNickname, groupRequest.FromUserFaceUrl, 0)
// if err != nil {
// return nil, err
// }
// } else if pb.Flag == -1 {
// err = dbConn.Exec("update `group_request` set flag = ?, handled_msg = ?, handled_user = ? where group_id = ? and to_user_id = ? and from_user_id = ?",
// pb.Flag, pb.RespMsg, pb.OwnerID, pb.GroupID, "0", pb.UID).Error
// if err != nil {
// return nil, err
// }
// } else {
// return nil, errors.New("flag error")
// }
//} else {
// if pb.Flag == 1 {
// err = dbConn.Exec("update `group_request` set flag = ?, handled_msg = ?, handled_user = ? where group_id = ? and to_user_id = ?",
// pb.Flag, pb.RespMsg, pb.OwnerID, pb.GroupID, pb.UID).Error
// if err != nil {
// return nil, err
// }
//
// // add to group member
// err = InsertIntoGroupMember(pb.GroupID, pb.UID, groupRequest.ToUserNickname, groupRequest.ToUserFaceUrl, 0)
// if err != nil {
// return nil, err
// }
// } else if pb.Flag == -1 {
// err = dbConn.Exec("update `group_request` set flag = ?, handled_msg = ?, handled_user = ? where group_id = ? and to_user_id = ?",
// pb.Flag, pb.RespMsg, pb.OwnerID, pb.GroupID, pb.UID).Error
// if err != nil {
// return nil, err
// }
// } else {
// return nil, errors.New("flag error")
// }
//}
return &group.GroupApplicationResponseResp{}, nil
}
@@ -0,0 +1,62 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
"time"
)
func InsertIntoGroupRequest(groupId, fromUserId, toUserId, reqMsg, fromUserNickName, fromUserFaceUrl string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
toInsertInfo := GroupRequest{GroupID: groupId, FromUserID: fromUserId, ToUserID: toUserId, ReqMsg: reqMsg, FromUserNickname: fromUserNickName, FromUserFaceUrl: fromUserFaceUrl, CreateTime: time.Now()}
err = dbConn.Table("group_request").Create(&toInsertInfo).Error
if err != nil {
return err
}
return nil
}
func FindGroupRequestUserInfoByGroupIDAndUid(groupId, uid string) (*GroupRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var requestUserInfo GroupRequest
err = dbConn.Table("group_request").Where("from_user_id=? and group_id=?", uid, groupId).Find(&requestUserInfo).Error
if err != nil {
return nil, err
}
return &requestUserInfo, nil
}
func DelGroupRequest(groupId, fromUserId, toUserId string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("delete from group_request where group_id=? and from_user_id=? and to_user_id=?", groupId, fromUserId, toUserId).Error
if err != nil {
return err
}
return nil
}
func FindGroupBeInvitedRequestInfoByUidAndGroupID(groupId, uid string) (*GroupRequest, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var beInvitedRequestUserInfo GroupRequest
err = dbConn.Table("group_request").Where("to_user_id=? and group_id=?", uid, groupId).Find(&beInvitedRequestUserInfo).Error
if err != nil {
return nil, err
}
return &beInvitedRequestUserInfo, nil
}
func InsertGroupRequest(groupId, fromUser, fromUserNickName, fromUserFaceUrl, toUser, requestMsg, handledMsg string, handleStatus int) error {
return nil
}
@@ -0,0 +1,70 @@
package im_mysql_model
import "time"
type User struct {
UID string `gorm:"column:uid"`
Name string `gorm:"column:name"`
Icon string `gorm:"column:icon"`
Gender int32 `gorm:"column:gender"`
Mobile string `gorm:"column:mobile"`
Birth string `gorm:"column:birth"`
Email string `gorm:"column:email"`
Ex string `gorm:"column:ex"`
CreateTime time.Time `gorm:"column:create_time"`
}
type Friend struct {
OwnerId string `gorm:"column:owner_id"`
FriendId string `gorm:"column:friend_id"`
Comment string `gorm:"column:comment"`
FriendFlag int32 `gorm:"column:friend_flag"`
CreateTime time.Time `gorm:"column:create_time"`
}
type FriendRequest struct {
ReqId string `gorm:"column:req_id"`
Uid string `gorm:"column:user_id"`
Flag int32 `gorm:"column:flag"`
ReqMessage string `gorm:"column:req_message"`
CreateTime time.Time `gorm:"column:create_time"`
}
type BlackList struct {
OwnerId string `gorm:"column:owner_id"`
BlockId string `gorm:"column:block_id"`
CreateTime time.Time `gorm:"column:create_time"`
}
type Group struct {
GroupId string `gorm:"column:group_id"`
Name string `gorm:"column:name"`
Introduction string `gorm:"column:introduction"`
Notification string `gorm:"column:notification"`
FaceUrl string `gorm:"column:face_url"`
CreateTime time.Time `gorm:"column:create_time"`
Ex string `gorm:"column:ex"`
}
type GroupMember struct {
GroupId string `gorm:"column:group_id"`
Uid string `gorm:"column:uid"`
NickName string `gorm:"column:nickname"`
AdministratorLevel int32 `gorm:"column:administrator_level"`
JoinTime time.Time `gorm:"column:join_time"`
UserGroupFaceUrl string `gorm:"user_group_face_url"`
}
type GroupRequest struct {
ID string `gorm:"column:id"`
GroupID string `gorm:"column:group_id"`
FromUserID string `gorm:"column:from_user_id"`
ToUserID string `gorm:"column:to_user_id"`
Flag int32 `gorm:"column:flag"`
ReqMsg string `gorm:"column:req_msg"`
HandledMsg string `gorm:"column:handled_msg"`
CreateTime time.Time `gorm:"column:create_time"`
FromUserNickname string `gorm:"from_user_nickname"`
ToUserNickname string `gorm:"to_user_nickname"`
FromUserFaceUrl string `gorm:"from_user_face_url"`
ToUserFaceUrl string `gorm:"to_user_face_url"`
HandledUser string `gorm:"handled_user"`
}
@@ -0,0 +1,48 @@
package im_mysql_model
import (
"Open_IM/pkg/common/db"
"time"
)
func InsertInToUserBlackList(ownerID, blockID string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
toInsertInfo := BlackList{OwnerId: ownerID, BlockId: blockID, CreateTime: time.Now()}
err = dbConn.Table("user_black_list").Create(toInsertInfo).Error
return err
}
func FindRelationshipFromBlackList(ownerID, blockID string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
var blackList BlackList
err = dbConn.Table("user_black_list").Where("owner_id=? and block_id=?", ownerID, blockID).Find(&blackList).Error
return err
}
func RemoveBlackList(ownerID, blockID string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Exec("delete from user_black_list where owner_id=? and block_id=?", ownerID, blockID).Error
return err
}
func GetBlackListByUID(ownerID string) ([]BlackList, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var blackListUsersInfo []BlackList
err = dbConn.Table("user_black_list").Where("owner_id=?", ownerID).Find(&blackListUsersInfo).Error
if err != nil {
return nil, err
}
return blackListUsersInfo, nil
}
@@ -0,0 +1,147 @@
package im_mysql_model
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/db"
pbAuth "Open_IM/pkg/proto/auth"
"Open_IM/pkg/utils"
_ "github.com/jinzhu/gorm/dialects/mysql"
"time"
)
func init() {
//init managers
var pb pbAuth.UserRegisterReq
for k, v := range config.Config.Manager.AppManagerUid {
if !IsExistUser(v) {
pb.UID = v
pb.Name = "AppManager" + utils.IntToString(k+1)
err := UserRegister(&pb)
if err != nil {
panic(err)
}
}
}
}
func UserRegister(pb *pbAuth.UserRegisterReq) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
addUser := User{
UID: pb.UID,
Name: pb.Name,
Icon: pb.Icon,
Gender: pb.Gender,
Mobile: pb.Mobile,
Birth: pb.Birth,
Email: pb.Email,
Ex: pb.Ex,
CreateTime: time.Now(),
}
err = dbConn.Table("user").Create(&addUser).Error
if err != nil {
return err
}
return nil
}
func UserDelete(uid string) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
err = dbConn.Table("user").Where("uid=?", uid).Delete(User{}).Error
if err != nil {
return err
}
return nil
}
func FindUserByUID(uid string) (*User, error) {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return nil, err
}
var user User
err = dbConn.Table("user").Where("uid=?", uid).First(&user).Error
if err != nil {
return nil, err
}
return &user, nil
}
func UpDateUserInfo(uid, name, headUrl, mobilePhoneNum, birth, email, extendInfo string, gender int32) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
if name != "" {
if err = dbConn.Exec("update user set name=? where uid=?", name, uid).Error; err != nil {
return err
}
}
if headUrl != "" {
if err = dbConn.Exec("update user set icon=? where uid=?", headUrl, uid).Error; err != nil {
return err
}
}
if mobilePhoneNum != "" {
if err = dbConn.Exec("update user set mobile=? where uid=?", mobilePhoneNum, uid).Error; err != nil {
return err
}
}
if birth != "" {
if err = dbConn.Exec("update user set birth=? where uid=?", birth, uid).Error; err != nil {
return err
}
}
if email != "" {
if err = dbConn.Exec("update user set email=? where uid=?", email, uid).Error; err != nil {
return err
}
}
if extendInfo != "" {
if err = dbConn.Exec("update user set ex=? where uid=?", extendInfo, uid).Error; err != nil {
return err
}
}
if gender != 0 {
if err = dbConn.Exec("update user set gender=? where uid=?", gender, uid).Error; err != nil {
return err
}
}
return nil
}
func SelectAllUID() ([]string, error) {
var uid []string
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return uid, err
}
rows, _ := dbConn.Raw("select uid from user").Rows()
defer rows.Close()
var strUID string
for rows.Next() {
rows.Scan(&strUID)
uid = append(uid, strUID)
}
return uid, nil
}
func IsExistUser(uid string) bool {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return false
}
var number int32
err = dbConn.Raw("select count(*) from `user` where uid = ?", uid).Count(&number).Error
if err != nil {
return false
}
if number != 1 {
return false
}
return true
}
@@ -0,0 +1,48 @@
/*
** description("").
** copyright('tuoyun,www.tuoyun.net').
** author("fg,Gordon@tuoyun.net").
** time(2021/3/4 11:18).
*/
package im_mysql_msg_model
import (
"Open_IM/pkg/common/db"
pbMsg "Open_IM/pkg/proto/chat"
"Open_IM/pkg/utils"
"database/sql"
"time"
)
// ChatLog Chat information table structure
type ChatLog struct {
MsgId string `gorm:"primary_key"` // Chat history primary key ID
SendID string `gorm:"column:send_id"` // Send ID
RecvID string `gorm:"column:recv_id"` //Receive ID
SendTime time.Time `gorm:"column:send_time"` // Send time
SessionType int32 `gorm:"column:session_type"` // Session type
ContentType int32 `gorm:"column:content_type"` // Message content type
MsgFrom int32 `gorm:"column:msg_from"` // Source, user, system
Content string `gorm:"column:content"` // Chat content
SenderPlatformID int32 `gorm:"column:sender_platform_id"` //The sender's platform ID
Remark sql.NullString `gorm:"column:remark"` // remark
}
func InsertMessageToChatLog(msgData pbMsg.WSToMsgSvrChatMsg) error {
dbConn, err := db.DB.MysqlDB.DefaultGormDB()
if err != nil {
return err
}
chatLog := ChatLog{
MsgId: msgData.MsgID,
SendID: msgData.SendID,
RecvID: msgData.RecvID,
SendTime: utils.UnixNanoSecondToTime(msgData.SendTime),
SessionType: msgData.SessionType,
ContentType: msgData.ContentType,
MsgFrom: msgData.MsgFrom,
Content: msgData.Content,
SenderPlatformID: msgData.PlatformID,
}
return dbConn.Table("chat_log").Create(chatLog).Error
}
@@ -0,0 +1,36 @@
package im_mysql_msg_model
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/db"
"hash/crc32"
"strconv"
)
func getHashMsgDBAddr(userID string) string {
hCode := crc32.ChecksumIEEE([]byte(userID))
return config.Config.Mysql.DBAddress[hCode%uint32(len(config.Config.Mysql.DBAddress))]
}
func getHashMsgTableIndex(userID string) int {
hCode := crc32.ChecksumIEEE([]byte(userID))
return int(hCode % uint32(config.Config.Mysql.DBMsgTableNum))
}
func QueryUserMsgID(userID string) ([]string, error) {
dbAddress, dbTableIndex := getHashMsgDBAddr(userID), getHashMsgTableIndex(userID)
dbTableName := "receive" + strconv.Itoa(dbTableIndex)
dbConn, _ := db.DB.MysqlDB.GormDB(dbAddress, config.Config.Mysql.DBTableName)
var msgID string
var msgIDList []string
rows, _ := dbConn.Raw("select msg_id from ? where user_id = ?", dbTableName, userID).Rows()
defer rows.Close()
for rows.Next() {
rows.Scan(&msgID)
msgIDList = append(msgIDList, msgID)
}
return msgIDList, nil
}
@@ -0,0 +1,36 @@
/*
** description("").
** copyright('tuoyun,www.tuoyun.net').
** author("fg,Gordon@tuoyun.net").
** time(2021/3/4 11:18).
*/
package im_mysql_msg_model
import (
"time"
)
// Receive Inbox table structure
type Receive struct {
UserId string `gorm:"primary_key"` // 收件箱主键ID
Seq int64 `gorm:"primary_key"` // 收件箱主键ID
MsgId string
CreateTime *time.Time
}
//func InsertMessageToReceive(seq int64, userid, msgid string) error {
// conn := db.NewDbConnection()
// receive := Receive{
// UID: userid,
// Seq: seq,
// MsgId: msgid,
// }
// err := conn.Table("receive").Create(&receive).Error
// return err
//}
//func GetBiggestSeqFromReceive(userid string) (seq int64, err error) {
// //得到数据库的连接(并非真连接,调用时才连接,由gorm自动维护数据库连接池)
// conn := db.NewDbConnection()
// err = conn.Raw("select max(seq) from receive where user_id = ?", userid).Row().Scan(&seq)
// return seq, err
//}
+92
View File
@@ -0,0 +1,92 @@
package db
import (
log2 "Open_IM/pkg/common/log"
"github.com/garyburd/redigo/redis"
)
const (
userIncrSeq = "REDIS_USER_INCR_SEQ:" // user incr seq
appleDeviceToken = "DEVICE_TOKEN"
lastGetSeq = "LAST_GET_SEQ"
)
func (d *DataBases) Exec(cmd string, key interface{}, args ...interface{}) (interface{}, error) {
con := d.redisPool.Get()
if err := con.Err(); err != nil {
log2.Error("", "", "redis cmd = %v, err = %v", cmd, err)
return nil, err
}
defer con.Close()
params := make([]interface{}, 0)
params = append(params, key)
if len(args) > 0 {
for _, v := range args {
params = append(params, v)
}
}
return con.Do(cmd, params...)
}
//执行用户消息的seq自增操作
func (d *DataBases) IncrUserSeq(uid string) (int64, error) {
key := userIncrSeq + uid
return redis.Int64(d.Exec("INCR", key))
}
//获取最新的seq
func (d *DataBases) GetUserSeq(uid string) (int64, error) {
key := userIncrSeq + uid
return redis.Int64(d.Exec("GET", key))
}
//存储苹果的设备token到redis
func (d *DataBases) SetAppleDeviceToken(accountAddress, value string) (err error) {
key := appleDeviceToken + accountAddress
_, err = d.Exec("SET", key, value)
return err
}
//删除苹果设备token
func (d *DataBases) DelAppleDeviceToken(accountAddress string) (err error) {
key := appleDeviceToken + accountAddress
_, err = d.Exec("DEL", key)
return err
}
//记录用户上一次主动拉取Seq的值
func (d *DataBases) SetLastGetSeq(uid string) (err error) {
key := lastGetSeq + uid
_, err = d.Exec("SET", key)
return err
}
//获取用户上一次主动拉取Seq的值
func (d *DataBases) GetLastGetSeq(uid string) (int64, error) {
key := userIncrSeq + uid
return redis.Int64(d.Exec("GET", key))
}
//Store userid and platform class to redis
func (d *DataBases) SetUserIDAndPlatform(userID, platformClass, value string, ttl int64) error {
key := userID + platformClass
_, err := d.Exec("SET", key, value, "EX", ttl)
return err
}
//Check exists userid and platform class from redis
func (d *DataBases) ExistsUserIDAndPlatform(userID, platformClass string) (interface{}, error) {
key := userID + platformClass
exists, err := d.Exec("EXISTS", key)
return exists, err
}
//Get platform class Token
func (d *DataBases) GetPlatformToken(userID, platformClass string) (interface{}, error) {
key := userID + platformClass
token, err := d.Exec("GET", key)
return token, err
}
+53
View File
@@ -0,0 +1,53 @@
/*
** description("").
** copyright('open-im,www.open-im.io').
** author("fg,Gordon@tuoyun.net").
** time(2021/5/27 10:31).
*/
package http
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"time"
)
func Get(url string) (response []byte, err error) {
client := http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
//application/json; charset=utf-8
func Post(url string, data interface{}, contentType string) (content []byte, err error) {
jsonStr, _ := json.Marshal(data)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
if err != nil {
return nil, err
}
req.Header.Add("content-type", contentType)
defer req.Body.Close()
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
result, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return result, nil
}
+36
View File
@@ -0,0 +1,36 @@
package kafka
import (
"github.com/Shopify/sarama"
"sync"
)
type Consumer struct {
addr []string
WG sync.WaitGroup
Topic string
PartitionList []int32
Consumer sarama.Consumer
}
func NewKafkaConsumer(addr []string, topic string) *Consumer {
p := Consumer{}
p.Topic = topic
p.addr = addr
consumer, err := sarama.NewConsumer(p.addr, nil)
if err != nil {
panic(err)
return nil
}
p.Consumer = consumer
partitionList, err := consumer.Partitions(p.Topic)
if err != nil {
panic(err)
return nil
}
p.PartitionList = partitionList
return &p
}
+53
View File
@@ -0,0 +1,53 @@
/*
** description("").
** copyright('tuoyun,www.tuoyun.net').
** author("fg,Gordon@tuoyun.net").
** time(2021/5/11 9:36).
*/
package kafka
import (
"context"
"github.com/Shopify/sarama"
)
type MConsumerGroup struct {
sarama.ConsumerGroup
groupID string
topics []string
}
type MConsumerGroupConfig struct {
KafkaVersion sarama.KafkaVersion
OffsetsInitial int64
IsReturnErr bool
}
func NewMConsumerGroup(consumerConfig *MConsumerGroupConfig, topics, addr []string, groupID string) *MConsumerGroup {
config := sarama.NewConfig()
config.Version = consumerConfig.KafkaVersion
config.Consumer.Offsets.Initial = consumerConfig.OffsetsInitial
config.Consumer.Return.Errors = consumerConfig.IsReturnErr
client, err := sarama.NewClient(addr, config)
if err != nil {
panic(err)
}
consumerGroup, err := sarama.NewConsumerGroupFromClient(groupID, client)
if err != nil {
panic(err)
}
return &MConsumerGroup{
consumerGroup,
groupID,
topics,
}
}
func (mc *MConsumerGroup) RegisterHandleAndConsumer(handler sarama.ConsumerGroupHandler) {
ctx := context.Background()
for {
err := mc.ConsumerGroup.Consume(ctx, mc.topics, handler)
if err != nil {
panic(err)
}
}
}
+49
View File
@@ -0,0 +1,49 @@
package kafka
import (
log2 "Open_IM/pkg/common/log"
"github.com/Shopify/sarama"
"github.com/golang/protobuf/proto"
)
type Producer struct {
topic string
addr []string
config *sarama.Config
producer sarama.SyncProducer
}
func NewKafkaProducer(addr []string, topic string) *Producer {
p := Producer{}
p.config = sarama.NewConfig() //Instantiate a sarama Config
p.config.Producer.Return.Successes = true //Whether to enable the successes channel to be notified after the message is sent successfully
p.config.Producer.RequiredAcks = sarama.WaitForAll //Set producer Message Reply level 0 1 all
p.config.Producer.Partitioner = sarama.NewHashPartitioner //Set the hash-key automatic hash partition. When sending a message, you must specify the key value of the message. If there is no key, the partition will be selected randomly
p.addr = addr
p.topic = topic
producer, err := sarama.NewSyncProducer(p.addr, p.config) //Initialize the client
if err != nil {
panic(err)
return nil
}
p.producer = producer
return &p
}
func (p *Producer) SendMessage(m proto.Message, key ...string) (int32, int64, error) {
kMsg := &sarama.ProducerMessage{}
kMsg.Topic = p.topic
if len(key) == 1 {
kMsg.Key = sarama.StringEncoder(key[0])
}
bMsg, err := proto.Marshal(m)
if err != nil {
log2.Error("", "", "proto marshal err = %s", err.Error())
return -1, -1, err
}
kMsg.Value = sarama.ByteEncoder(bMsg)
return p.producer.SendMessage(kMsg)
}
@@ -0,0 +1,73 @@
package multi_terminal_login
import (
"Open_IM/internal/push/content_struct"
"Open_IM/internal/push/logic"
pbChat "Open_IM/pkg/proto/chat"
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/constant"
"Open_IM/pkg/common/db"
"Open_IM/pkg/common"
)
func MultiTerminalLoginChecker(uid, token string, platformID int32) error {
// 1.check userid and platform class 0 not exists and 1 exists
existsInterface, err := db.DB.ExistsUserIDAndPlatform(uid, utils.PlatformNameToClass(utils.PlatformIDToName(platformID)))
if err != nil {
return err
}
exists := existsInterface.(int64)
//get config multi login policy
if config.Config.MultiLoginPolicy.OnlyOneTerminalAccess {
//OnlyOneTerminalAccess policy need to check all terminal
if utils.PlatformNameToClass(utils.PlatformIDToName(platformID)) == "PC" {
existsInterface, err = db.DB.ExistsUserIDAndPlatform(uid, "Mobile")
if err != nil {
return err
}
} else {
existsInterface, err = db.DB.ExistsUserIDAndPlatform(uid, "PC")
if err != nil {
return err
}
}
exists = existsInterface.(int64)
if exists == 1 {
err := db.DB.SetUserIDAndPlatform(uid, utils.PlatformNameToClass(utils.PlatformIDToName(platformID)), token, config.Config.TokenPolicy.AccessExpire)
if err != nil {
return err
}
PushMessageToTheTerminal(uid, platformID)
return nil
}
} else if config.Config.MultiLoginPolicy.MobileAndPCTerminalAccessButOtherTerminalKickEachOther {
// common terminal need to kick eich other
if exists == 1 {
err := db.DB.SetUserIDAndPlatform(uid, utils.PlatformNameToClass(utils.PlatformIDToName(platformID)), token, config.Config.TokenPolicy.AccessExpire)
if err != nil {
return err
}
PushMessageToTheTerminal(uid, platformID)
return nil
}
}
err = db.DB.SetUserIDAndPlatform(uid, utils.PlatformNameToClass(utils.PlatformIDToName(platformID)), token, config.Config.TokenPolicy.AccessExpire)
if err != nil {
return err
}
PushMessageToTheTerminal(uid, platformID)
return nil
}
func PushMessageToTheTerminal(uid string, platform int32) {
logic.SendMsgByWS(&pbChat.WSToMsgSvrChatMsg{
SendID: uid,
RecvID: uid,
Content: content_struct.NewContentStructString(1, "", "Your account is already logged on other terminal,please confirm"),
SendTime: utils.GetCurrentTimestampBySecond(),
MsgFrom: constant.SysMsgType,
ContentType: constant.KickOnlineTip,
PlatformID: platform,
})
}
+254
View File
@@ -0,0 +1,254 @@
// Package grpcpool provides a pool of grpc clients
package getcdv3
import (
"context"
"errors"
"sync"
"time"
"google.golang.org/grpc"
)
var (
// ErrClosed is the error when the client pool is closed
ErrClosed = errors.New("grpc pool: client pool is closed")
// ErrTimeout is the error when the client pool timed out
ErrTimeout = errors.New("grpc pool: client pool timed out")
// ErrAlreadyClosed is the error when the client conn was already closed
ErrAlreadyClosed = errors.New("grpc pool: the connection was already closed")
// ErrFullPool is the error when the pool is already full
ErrFullPool = errors.New("grpc pool: closing a ClientConn into a full pool")
)
// Factory is a function type creating a grpc client
type Factory func(schema, etcdaddr, servicename string) (*grpc.ClientConn, error)
// FactoryWithContext is a function type creating a grpc client
// that accepts the context parameter that could be passed from
// Get or NewWithContext method.
type FactoryWithContext func(context.Context) (*grpc.ClientConn, error)
// Pool is the grpc client pool
type Pool struct {
clients chan ClientConn
factory FactoryWithContext
idleTimeout time.Duration
maxLifeDuration time.Duration
mu sync.RWMutex
}
// ClientConn is the wrapper for a grpc client conn
type ClientConn struct {
*grpc.ClientConn
pool *Pool
timeUsed time.Time
timeInitiated time.Time
unhealthy bool
}
// New creates a new clients pool with the given initial and maximum capacity,
// and the timeout for the idle clients. Returns an error if the initial
// clients could not be created
func New(factory Factory, schema, etcdaddr, servicename string, init, capacity int, idleTimeout time.Duration,
maxLifeDuration ...time.Duration) (*Pool, error) {
return NewWithContext(context.Background(), func(ctx context.Context) (*grpc.ClientConn, error) { return factory(schema, etcdaddr, servicename) },
init, capacity, idleTimeout, maxLifeDuration...)
}
// NewWithContext creates a new clients pool with the given initial and maximum
// capacity, and the timeout for the idle clients. The context parameter would
// be passed to the factory method during initialization. Returns an error if the
// initial clients could not be created.
func NewWithContext(ctx context.Context, factory FactoryWithContext, init, capacity int, idleTimeout time.Duration,
maxLifeDuration ...time.Duration) (*Pool, error) {
if capacity <= 0 {
capacity = 1
}
if init < 0 {
init = 0
}
if init > capacity {
init = capacity
}
p := &Pool{
clients: make(chan ClientConn, capacity),
factory: factory,
idleTimeout: idleTimeout,
}
if len(maxLifeDuration) > 0 {
p.maxLifeDuration = maxLifeDuration[0]
}
for i := 0; i < init; i++ {
c, err := factory(ctx)
if err != nil {
return nil, err
}
p.clients <- ClientConn{
ClientConn: c,
pool: p,
timeUsed: time.Now(),
timeInitiated: time.Now(),
}
}
// Fill the rest of the pool with empty clients
for i := 0; i < capacity-init; i++ {
p.clients <- ClientConn{
pool: p,
}
}
return p, nil
}
func (p *Pool) getClients() chan ClientConn {
p.mu.RLock()
defer p.mu.RUnlock()
return p.clients
}
// Close empties the pool calling Close on all its clients.
// You can call Close while there are outstanding clients.
// The pool channel is then closed, and Get will not be allowed anymore
func (p *Pool) Close() {
p.mu.Lock()
clients := p.clients
p.clients = nil
p.mu.Unlock()
if clients == nil {
return
}
close(clients)
for client := range clients {
if client.ClientConn == nil {
continue
}
client.ClientConn.Close()
}
}
// IsClosed returns true if the client pool is closed.
func (p *Pool) IsClosed() bool {
return p == nil || p.getClients() == nil
}
// Get will return the next available client. If capacity
// has not been reached, it will create a new one using the factory. Otherwise,
// it will wait till the next client becomes available or a timeout.
// A timeout of 0 is an indefinite wait
func (p *Pool) Get(ctx context.Context) (*ClientConn, error) {
clients := p.getClients()
if clients == nil {
return nil, ErrClosed
}
wrapper := ClientConn{
pool: p,
}
select {
case wrapper = <-clients:
// All good
case <-ctx.Done():
return nil, ErrTimeout // it would better returns ctx.Err()
}
// If the wrapper was idle too long, close the connection and create a new
// one. It's safe to assume that there isn't any newer client as the client
// we fetched is the first in the channel
idleTimeout := p.idleTimeout
if wrapper.ClientConn != nil && idleTimeout > 0 &&
wrapper.timeUsed.Add(idleTimeout).Before(time.Now()) {
wrapper.ClientConn.Close()
wrapper.ClientConn = nil
}
var err error
if wrapper.ClientConn == nil {
wrapper.ClientConn, err = p.factory(ctx)
if err != nil {
// If there was an error, we want to put back a placeholder
// client in the channel
clients <- ClientConn{
pool: p,
}
}
// This is a new connection, reset its initiated time
wrapper.timeInitiated = time.Now()
}
return &wrapper, err
}
// Unhealthy marks the client conn as unhealthy, so that the connection
// gets reset when closed
func (c *ClientConn) Unhealthy() {
c.unhealthy = true
}
// Close returns a ClientConn to the pool. It is safe to call multiple time,
// but will return an error after first time
func (c *ClientConn) Close() error {
if c == nil {
return nil
}
if c.ClientConn == nil {
return ErrAlreadyClosed
}
if c.pool.IsClosed() {
return ErrClosed
}
// If the wrapper connection has become too old, we want to recycle it. To
// clarify the logic: if the sum of the initialization time and the max
// duration is before Now(), it means the initialization is so old adding
// the maximum duration couldn't put in the future. This sum therefore
// corresponds to the cut-off point: if it's in the future we still have
// time, if it's in the past it's too old
maxDuration := c.pool.maxLifeDuration
if maxDuration > 0 && c.timeInitiated.Add(maxDuration).Before(time.Now()) {
c.Unhealthy()
}
// We're cloning the wrapper so we can set ClientConn to nil in the one
// used by the user
wrapper := ClientConn{
pool: c.pool,
ClientConn: c.ClientConn,
timeUsed: time.Now(),
}
if c.unhealthy {
wrapper.ClientConn.Close()
wrapper.ClientConn = nil
} else {
wrapper.timeInitiated = c.timeInitiated
}
select {
case c.pool.clients <- wrapper:
// All good
default:
return ErrFullPool
}
c.ClientConn = nil // Mark as closed
return nil
}
// Capacity returns the capacity
func (p *Pool) Capacity() int {
if p.IsClosed() {
return 0
}
return cap(p.clients)
}
// Available returns the number of currently unused clients
func (p *Pool) Available() int {
if p.IsClosed() {
return 0
}
return len(p.clients)
}
+95
View File
@@ -0,0 +1,95 @@
package getcdv3
import (
"context"
"fmt"
"go.etcd.io/etcd/clientv3"
"net"
"strconv"
"strings"
)
type RegEtcd struct {
cli *clientv3.Client
ctx context.Context
cancel context.CancelFunc
key string
}
var rEtcd *RegEtcd
// "%s:///%s/"
func GetPrefix(schema, serviceName string) string {
return fmt.Sprintf("%s:///%s/", schema, serviceName)
}
// "%s:///%s"
func GetPrefix4Unique(schema, serviceName string) string {
return fmt.Sprintf("%s:///%s", schema, serviceName)
}
// "%s:///%s/" -> "%s:///%s:ip:port"
func RegisterEtcd4Unique(schema, etcdAddr, myHost string, myPort int, serviceName string, ttl int) error {
serviceName = serviceName + ":" + net.JoinHostPort(myHost, strconv.Itoa(myPort))
return RegisterEtcd(schema, etcdAddr, myHost, myPort, serviceName, ttl)
}
//etcdAddr separated by commas
func RegisterEtcd(schema, etcdAddr, myHost string, myPort int, serviceName string, ttl int) error {
cli, err := clientv3.New(clientv3.Config{
Endpoints: strings.Split(etcdAddr, ","),
})
fmt.Println("RegisterEtcd")
if err != nil {
// return fmt.Errorf("grpclb: create clientv3 client failed: %v", err)
return fmt.Errorf("create etcd clientv3 client failed, errmsg:%v, etcd addr:%s", err, etcdAddr)
}
//lease
ctx, cancel := context.WithCancel(context.Background())
resp, err := cli.Grant(ctx, int64(ttl))
if err != nil {
return fmt.Errorf("grant failed")
}
// schema:///serviceName/ip:port ->ip:port
serviceValue := net.JoinHostPort(myHost, strconv.Itoa(myPort))
serviceKey := GetPrefix(schema, serviceName) + serviceValue
//set key->value
if _, err := cli.Put(ctx, serviceKey, serviceValue, clientv3.WithLease(resp.ID)); err != nil {
return fmt.Errorf("put failed, errmsg:%v key:%s, value:%s", err, serviceKey, serviceValue)
}
//keepalive
kresp, err := cli.KeepAlive(ctx, resp.ID)
if err != nil {
return fmt.Errorf("keepalive faild, errmsg:%v, lease id:%d", err, resp.ID)
}
go func() {
FLOOP:
for {
select {
case _, ok := <-kresp:
if ok == true {
} else {
break FLOOP
}
}
}
}()
rEtcd = &RegEtcd{ctx: ctx,
cli: cli,
cancel: cancel,
key: serviceKey}
return nil
}
func UnRegisterEtcd() {
//delete
rEtcd.cancel()
rEtcd.cli.Delete(rEtcd.ctx, rEtcd.key)
}
+262
View File
@@ -0,0 +1,262 @@
package getcdv3
import (
"context"
"fmt"
"go.etcd.io/etcd/clientv3"
"go.etcd.io/etcd/mvcc/mvccpb"
//"google.golang.org/genproto/googleapis/ads/googleads/v1/services"
"google.golang.org/grpc"
"google.golang.org/grpc/balancer/roundrobin"
"google.golang.org/grpc/resolver"
"strings"
"sync"
"time"
)
type Resolver struct {
cc resolver.ClientConn
serviceName string
grpcClientConn *grpc.ClientConn
cli *clientv3.Client
schema string
etcdAddr string
watchStartRevision int64
}
var (
nameResolver = make(map[string]*Resolver)
rwNameResolverMutex sync.RWMutex
)
func NewResolver(schema, etcdAddr, serviceName string) (*Resolver, error) {
etcdCli, err := clientv3.New(clientv3.Config{
Endpoints: strings.Split(etcdAddr, ","),
})
if err != nil {
return nil, err
}
var r Resolver
r.serviceName = serviceName
r.cli = etcdCli
r.schema = schema
r.etcdAddr = etcdAddr
resolver.Register(&r)
conn, err := grpc.Dial(
GetPrefix(schema, serviceName),
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name)),
grpc.WithInsecure(),
grpc.WithTimeout(time.Duration(5)*time.Second),
)
if err == nil {
r.grpcClientConn = conn
}
return &r, err
}
func (r1 *Resolver) ResolveNow(rn resolver.ResolveNowOptions) {
}
func (r1 *Resolver) Close() {
}
func GetConn(schema, etcdaddr, serviceName string) *grpc.ClientConn {
rwNameResolverMutex.RLock()
r, ok := nameResolver[schema+serviceName]
rwNameResolverMutex.RUnlock()
if ok {
return r.grpcClientConn
}
rwNameResolverMutex.Lock()
r, ok = nameResolver[schema+serviceName]
if ok {
rwNameResolverMutex.Unlock()
return r.grpcClientConn
}
r, err := NewResolver(schema, etcdaddr, serviceName)
if err != nil {
rwNameResolverMutex.Unlock()
return nil
}
nameResolver[schema+serviceName] = r
rwNameResolverMutex.Unlock()
return r.grpcClientConn
}
func (r *Resolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
if r.cli == nil {
return nil, fmt.Errorf("etcd clientv3 client failed, etcd:%s", target)
}
r.cc = cc
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
// "%s:///%s"
prefix := GetPrefix(r.schema, r.serviceName)
// get key first
resp, err := r.cli.Get(ctx, prefix, clientv3.WithPrefix())
if err == nil {
var addrList []resolver.Address
for i := range resp.Kvs {
fmt.Println("init addr: ", string(resp.Kvs[i].Value))
addrList = append(addrList, resolver.Address{Addr: string(resp.Kvs[i].Value)})
}
r.cc.UpdateState(resolver.State{Addresses: addrList})
r.watchStartRevision = resp.Header.Revision + 1
go r.watch(prefix, addrList)
} else {
return nil, fmt.Errorf("etcd get failed, prefix: %s", prefix)
}
return r, nil
}
func (r *Resolver) Scheme() string {
return r.schema
}
func exists(addrList []resolver.Address, addr string) bool {
for _, v := range addrList {
if v.Addr == addr {
return true
}
}
return false
}
func remove(s []resolver.Address, addr string) ([]resolver.Address, bool) {
for i := range s {
if s[i].Addr == addr {
s[i] = s[len(s)-1]
return s[:len(s)-1], true
}
}
return nil, false
}
func (r *Resolver) watch(prefix string, addrList []resolver.Address) {
rch := r.cli.Watch(context.Background(), prefix, clientv3.WithPrefix(), clientv3.WithPrefix())
for n := range rch {
flag := 0
for _, ev := range n.Events {
switch ev.Type {
case mvccpb.PUT:
if !exists(addrList, string(ev.Kv.Value)) {
flag = 1
addrList = append(addrList, resolver.Address{Addr: string(ev.Kv.Value)})
fmt.Println("after add, new list: ", addrList)
}
case mvccpb.DELETE:
fmt.Println("remove addr key: ", string(ev.Kv.Key), "value:", string(ev.Kv.Value))
i := strings.LastIndexAny(string(ev.Kv.Key), "/")
if i < 0 {
return
}
t := string(ev.Kv.Key)[i+1:]
fmt.Println("remove addr key: ", string(ev.Kv.Key), "value:", string(ev.Kv.Value), "addr:", t)
if s, ok := remove(addrList, t); ok {
flag = 1
addrList = s
fmt.Println("after remove, new list: ", addrList)
}
}
}
if flag == 1 {
r.cc.UpdateState(resolver.State{Addresses: addrList})
fmt.Println("update: ", addrList)
}
}
}
func GetConn4Unique(schema, etcdaddr, servicename string) []*grpc.ClientConn {
gEtcdCli, err := clientv3.New(clientv3.Config{Endpoints: strings.Split(etcdaddr, ",")})
if err != nil {
fmt.Println("eeeeeeeeeeeee", err.Error())
return nil
}
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
// "%s:///%s"
prefix := GetPrefix4Unique(schema, servicename)
resp, err := gEtcdCli.Get(ctx, prefix, clientv3.WithPrefix())
// "%s:///%s:ip:port" -> %s:ip:port
allService := make([]string, 0)
if err == nil {
for i := range resp.Kvs {
k := string(resp.Kvs[i].Key)
b := strings.LastIndex(k, "///")
k1 := k[b+len("///"):]
e := strings.Index(k1, "/")
k2 := k1[:e]
allService = append(allService, k2)
}
} else {
gEtcdCli.Close()
fmt.Println("rrrrrrrrrrr", err.Error())
return nil
}
gEtcdCli.Close()
allConn := make([]*grpc.ClientConn, 0)
for _, v := range allService {
r := GetConn(schema, etcdaddr, v)
allConn = append(allConn, r)
}
return allConn
}
var (
service2pool = make(map[string]*Pool)
service2poolMu sync.Mutex
)
func GetconnFactory(schema, etcdaddr, servicename string) (*grpc.ClientConn, error) {
c := GetConn(schema, etcdaddr, servicename)
if c != nil {
return c, nil
} else {
return c, fmt.Errorf("GetConn failed")
}
}
func GetConnPool(schema, etcdaddr, servicename string) (*ClientConn, error) {
//get pool
p := NewPool(schema, etcdaddr, servicename)
//poo->get
ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(1000*time.Millisecond))
c, err := p.Get(ctx)
fmt.Println(err)
return c, err
}
func NewPool(schema, etcdaddr, servicename string) *Pool {
if _, ok := service2pool[schema+servicename]; !ok {
//
service2poolMu.Lock()
if _, ok1 := service2pool[schema+servicename]; !ok1 {
p, err := New(GetconnFactory, schema, etcdaddr, servicename, 5, 10, 1)
if err == nil {
service2pool[schema+servicename] = p
}
}
service2poolMu.Unlock()
}
return service2pool[schema+servicename]
}
func GetGrpcConn(schema, etcdaddr, servicename string) *grpc.ClientConn {
return nameResolver[schema+servicename].grpcClientConn
}
+23
View File
@@ -0,0 +1,23 @@
package utils
import (
"github.com/gin-gonic/gin"
"net/http"
)
func CorsHandler() gin.HandlerFunc {
return func(context *gin.Context) {
context.Writer.Header().Set("Access-Control-Allow-Origin", "*")
context.Header("Access-Control-Allow-Methods", "*")
context.Header("Access-Control-Allow-Headers", "*")
context.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
context.Header("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒
context.Header("Access-Control-Allow-Credentials", "false") // 跨域请求是否需要带cookie信息 默认设置为true
context.Header("content-type", "application/json") // 设置返回格式是json
//Release all option pre-requests
if context.Request.Method == http.MethodOptions {
context.JSON(http.StatusOK, "Options Request!")
}
context.Next()
}
}
+22
View File
@@ -0,0 +1,22 @@
package utils
import "os"
// Determine whether the given path is a folder
func IsDir(path string) bool {
s, err := os.Stat(path)
if err != nil {
return false
}
return s.IsDir()
}
// Determine whether the given path is a file
func IsFile(path string) bool {
return !IsDir(path)
}
// Create a directory
func MkDir(path string) error {
return os.MkdirAll(path, os.ModePerm)
}
+35
View File
@@ -0,0 +1,35 @@
package utils
import (
"Open_IM/pkg/common/config"
"net"
)
var ServerIP = ""
func init() {
//fixme In the configuration file, ip takes precedence, if not, get the valid network card ip of the machine
if config.Config.ServerIP != "" {
ServerIP = config.Config.ServerIP
return
}
//fixme Get the ip of the local network card
netInterfaces, err := net.Interfaces()
if err != nil {
panic(err)
}
for i := 0; i < len(netInterfaces); i++ {
//Exclude useless network cards by judging the net.flag Up flag
if (netInterfaces[i].Flags & net.FlagUp) != 0 {
address, _ := netInterfaces[i].Addrs()
for _, addr := range address {
if ipNet, ok := addr.(*net.IPNet); ok && !ipNet.IP.IsLoopback() {
if ipNet.IP.To4() != nil {
ServerIP = ipNet.IP.String()
return
}
}
}
}
}
}
+56
View File
@@ -0,0 +1,56 @@
package utils
import (
"errors"
"github.com/nfnt/resize"
"golang.org/x/image/bmp"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io"
"os"
)
func GenSmallImage(src, dst string) error {
fIn, _ := os.Open(src)
defer fIn.Close()
fOut, _ := os.Create(dst)
defer fOut.Close()
if err := scale(fIn, fOut, 0, 0, 0); err != nil {
return err
}
return nil
}
func scale(in io.Reader, out io.Writer, width, height, quality int) error {
origin, fm, err := image.Decode(in)
if err != nil {
return err
}
if width == 0 || height == 0 {
width = origin.Bounds().Max.X / 2
height = origin.Bounds().Max.Y / 2
}
if quality == 0 {
quality = 25
}
canvas := resize.Thumbnail(uint(width), uint(height), origin, resize.Lanczos3)
switch fm {
case "jpeg":
return jpeg.Encode(out, canvas, &jpeg.Options{quality})
case "png":
return png.Encode(out, canvas)
case "gif":
return gif.Encode(out, canvas, &gif.Options{})
case "bmp":
return bmp.Encode(out, canvas)
default:
return errors.New("ERROR FORMAT")
}
return nil
}
+193
View File
@@ -0,0 +1,193 @@
package utils
import (
"Open_IM/pkg/common/config"
"Open_IM/pkg/common/db"
"errors"
"github.com/dgrijalva/jwt-go"
"time"
)
var (
TokenExpired = errors.New("token is timed out, please log in again")
TokenInvalid = errors.New("token has been invalidated")
TokenNotValidYet = errors.New("token not active yet")
TokenMalformed = errors.New("that's not even a token")
TokenUnknown = errors.New("couldn't handle this token")
)
type Claims struct {
UID string
Platform string //login platform
jwt.StandardClaims
}
func BuildClaims(uid, accountAddr, platform string, ttl int64) Claims {
now := time.Now().Unix()
//if ttl=-1 Permanent token
if ttl == -1 {
return Claims{
UID: uid,
Platform: platform,
StandardClaims: jwt.StandardClaims{
ExpiresAt: -1,
IssuedAt: now,
NotBefore: now,
}}
}
return Claims{
UID: uid,
Platform: platform,
StandardClaims: jwt.StandardClaims{
ExpiresAt: now + ttl, //Expiration time
IssuedAt: now, //Issuing time
NotBefore: now, //Begin Effective time
}}
}
func CreateToken(userID, accountAddr string, platform int32) (string, int64, error) {
claims := BuildClaims(userID, accountAddr, PlatformIDToName(platform), config.Config.TokenPolicy.AccessExpire)
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte(config.Config.TokenPolicy.AccessSecret))
return tokenString, claims.ExpiresAt, err
}
func secret() jwt.Keyfunc {
return func(token *jwt.Token) (interface{}, error) {
return []byte(config.Config.TokenPolicy.AccessSecret), nil
}
}
func ParseToken(tokensString string) (claims *Claims, err error) {
token, err := jwt.ParseWithClaims(tokensString, &Claims{}, secret())
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, TokenMalformed
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
return nil, TokenExpired
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, TokenNotValidYet
} else {
return nil, TokenUnknown
}
}
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
// 1.check userid and platform class 0 not exists and 1 exists
existsInterface, err := db.DB.ExistsUserIDAndPlatform(claims.UID, Platform2class[claims.Platform])
if err != nil {
return nil, err
}
exists := existsInterface.(int64)
//get config multi login policy
if config.Config.MultiLoginPolicy.OnlyOneTerminalAccess {
//OnlyOneTerminalAccess policy need to check all terminal
//When only one end is allowed to log in, there is a situation that needs to be paid attention to. After PC login,
//mobile login should check two platform times. One of them is less than the redis storage time, which is the invalid token.
if Platform2class[claims.Platform] == "PC" {
existsInterface, err = db.DB.ExistsUserIDAndPlatform(claims.UID, "Mobile")
if err != nil {
return nil, err
}
exists = existsInterface.(int64)
if exists == 1 {
res, err := MakeTheTokenInvalid(*claims, "Mobile")
if err != nil {
return nil, err
}
if res {
return nil, TokenInvalid
}
}
} else {
existsInterface, err = db.DB.ExistsUserIDAndPlatform(claims.UID, "PC")
if err != nil {
return nil, err
}
exists = existsInterface.(int64)
if exists == 1 {
res, err := MakeTheTokenInvalid(*claims, "PC")
if err != nil {
return nil, err
}
if res {
return nil, TokenInvalid
}
}
}
if exists == 1 {
res, err := MakeTheTokenInvalid(*claims, Platform2class[claims.Platform])
if err != nil {
return nil, err
}
if res {
return nil, TokenInvalid
}
}
} else if config.Config.MultiLoginPolicy.MobileAndPCTerminalAccessButOtherTerminalKickEachOther {
if exists == 1 {
res, err := MakeTheTokenInvalid(*claims, Platform2class[claims.Platform])
if err != nil {
return nil, err
}
if res {
return nil, TokenInvalid
}
}
}
return claims, nil
}
return nil, TokenUnknown
}
func MakeTheTokenInvalid(currentClaims Claims, platformClass string) (bool, error) {
storedRedisTokenInterface, err := db.DB.GetPlatformToken(currentClaims.UID, platformClass)
if err != nil {
return false, err
}
storedRedisPlatformClaims, err := ParseRedisInterfaceToken(storedRedisTokenInterface)
if err != nil {
return false, err
}
//if issue time less than redis token then make this token invalid
if currentClaims.IssuedAt < storedRedisPlatformClaims.IssuedAt {
return true, TokenInvalid
}
return false, nil
}
func ParseRedisInterfaceToken(redisToken interface{}) (*Claims, error) {
token, err := jwt.ParseWithClaims(string(redisToken.([]uint8)), &Claims{}, secret())
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, TokenMalformed
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
return nil, TokenExpired
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, TokenNotValidYet
} else {
return nil, TokenInvalid
}
}
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, err
}
//Validation token, false means failure, true means successful verification
func VerifyToken(token, uid string) bool {
claims, err := ParseToken(token)
if err != nil {
return false
} else if claims.UID != uid {
return false
} else {
return true
}
}
+118
View File
@@ -0,0 +1,118 @@
package utils
import (
"encoding/json"
"sync"
)
type Map struct {
sync.RWMutex
m map[interface{}]interface{}
}
func (m *Map) init() {
if m.m == nil {
m.m = make(map[interface{}]interface{})
}
}
func (m *Map) UnsafeGet(key interface{}) interface{} {
if m.m == nil {
return nil
} else {
return m.m[key]
}
}
func (m *Map) Get(key interface{}) interface{} {
m.RLock()
defer m.RUnlock()
return m.UnsafeGet(key)
}
func (m *Map) UnsafeSet(key interface{}, value interface{}) {
m.init()
m.m[key] = value
}
func (m *Map) Set(key interface{}, value interface{}) {
m.Lock()
defer m.Unlock()
m.UnsafeSet(key, value)
}
func (m *Map) TestAndSet(key interface{}, value interface{}) interface{} {
m.Lock()
defer m.Unlock()
m.init()
if v, ok := m.m[key]; ok {
return v
} else {
m.m[key] = value
return nil
}
}
func (m *Map) UnsafeDel(key interface{}) {
m.init()
delete(m.m, key)
}
func (m *Map) Del(key interface{}) {
m.Lock()
defer m.Unlock()
m.UnsafeDel(key)
}
func (m *Map) UnsafeLen() int {
if m.m == nil {
return 0
} else {
return len(m.m)
}
}
func (m *Map) Len() int {
m.RLock()
defer m.RUnlock()
return m.UnsafeLen()
}
func (m *Map) UnsafeRange(f func(interface{}, interface{})) {
if m.m == nil {
return
}
for k, v := range m.m {
f(k, v)
}
}
func (m *Map) RLockRange(f func(interface{}, interface{})) {
m.RLock()
defer m.RUnlock()
m.UnsafeRange(f)
}
func (m *Map) LockRange(f func(interface{}, interface{})) {
m.Lock()
defer m.Unlock()
m.UnsafeRange(f)
}
func MapToJsonString(param map[string]interface{}) string {
dataType, _ := json.Marshal(param)
dataString := string(dataType)
return dataString
}
func JsonStringToMap(str string) (tempMap map[string]interface{}) {
_ = json.Unmarshal([]byte(str), &tempMap)
return tempMap
}
func GetSwitchFromOptions(Options map[string]interface{}, key string) (result bool) {
if flag, ok := Options[key]; !ok || flag == 1 {
return true
}
return false
}
+13
View File
@@ -0,0 +1,13 @@
package utils
import (
"crypto/md5"
"encoding/hex"
)
func Md5(s string) string {
h := md5.New()
h.Write([]byte(s))
cipher := h.Sum(nil)
return hex.EncodeToString(cipher)
}
+66
View File
@@ -0,0 +1,66 @@
package utils
// fixme 1<--->IOS 2<--->Android 3<--->Windows
//fixme 4<--->OSX 5<--->Web 6<--->MiniWeb 7<--->Linux
const (
//Platform ID
IOSPlatformID = 1
AndroidPlatformID = 2
WindowsPlatformID = 3
OSXPlatformID = 4
WebPlatformID = 5
MiniWebPlatformID = 6
LinuxPlatformID = 7
//Platform string match to Platform ID
IOSPlatformStr = "IOS"
AndroidPlatformStr = "Android"
WindowsPlatformStr = "Windows"
OSXPlatformStr = "OSX"
WebPlatformStr = "Web"
MiniWebPlatformStr = "MiniWeb"
LinuxPlatformStr = "Linux"
//terminal types
TerminalPC = "PC"
TerminalMobile = "Mobile"
)
var PlatformID2Name = map[int32]string{
IOSPlatformID: IOSPlatformStr,
AndroidPlatformID: AndroidPlatformStr,
WindowsPlatformID: WindowsPlatformStr,
OSXPlatformID: OSXPlatformStr,
WebPlatformID: WebPlatformStr,
MiniWebPlatformID: MiniWebPlatformStr,
LinuxPlatformID: LinuxPlatformStr,
}
var PlatformName2ID = map[string]int32{
IOSPlatformStr: IOSPlatformID,
AndroidPlatformStr: AndroidPlatformID,
WindowsPlatformStr: WindowsPlatformID,
OSXPlatformStr: OSXPlatformID,
WebPlatformStr: WebPlatformID,
MiniWebPlatformStr: MiniWebPlatformID,
LinuxPlatformStr: LinuxPlatformID,
}
var Platform2class = map[string]string{
IOSPlatformStr: TerminalMobile,
AndroidPlatformStr: TerminalMobile,
MiniWebPlatformStr: TerminalMobile,
WindowsPlatformStr: TerminalPC,
OSXPlatformStr: TerminalPC,
WebPlatformStr: TerminalPC,
LinuxPlatformStr: TerminalPC,
}
func PlatformIDToName(num int32) string {
return PlatformID2Name[num]
}
func PlatformNameToID(name string) int32 {
return PlatformName2ID[name]
}
func PlatformNameToClass(name string) string {
return Platform2class[name]
}
+64
View File
@@ -0,0 +1,64 @@
/*
** description("").
** copyright('tuoyun,www.tuoyun.net').
** author("fg,Gordon@tuoyun.net").
** time(2021/4/8 15:09).
*/
package utils
import (
"encoding/json"
"math/rand"
"strconv"
)
func IntToString(i int) string {
return strconv.FormatInt(int64(i), 10)
}
func StringToInt(i string) int {
j, _ := strconv.Atoi(i)
return j
}
func StringToInt64(i string) int64 {
j, _ := strconv.ParseInt(i, 10, 64)
return j
}
//judge a string whether in the string list
func IsContain(target string, List []string) bool {
for _, element := range List {
if target == element {
return true
}
}
return false
}
func InterfaceArrayToStringArray(data []interface{}) (i []string) {
for _, param := range data {
i = append(i, param.(string))
}
return i
}
func StructToJsonString(param interface{}) string {
dataType, _ := json.Marshal(param)
dataString := string(dataType)
return dataString
}
//The incoming parameter must be a pointer
func JsonStringToStruct(s string, args interface{}) error {
err := json.Unmarshal([]byte(s), args)
return err
}
func GetMsgID(sendID string) string {
t := int64ToString(GetCurrentTimestampByNano())
return Md5(t + sendID + int64ToString(rand.Int63n(GetCurrentTimestampByNano())))
}
func int64ToString(i int64) string {
return strconv.FormatInt(i, 10)
}
+77
View File
@@ -0,0 +1,77 @@
/*
** description("").
** copyright('tuoyun,www.tuoyun.net').
** author("fg,Gordon@tuoyun.net").
** time(2021/2/22 11:52).
*/
package utils
import (
"strconv"
"time"
)
const (
TimeOffset = 8 * 3600 //8 hour offset
HalfOffset = 12 * 3600 //Half-day hourly offset
)
//Get the current timestamp by Second
func GetCurrentTimestampBySecond() int64 {
return time.Now().Unix()
}
//Convert timestamp to time.Time type
func UnixSecondToTime(second int64) time.Time {
return time.Unix(second, 0)
}
//Convert nano timestamp to time.Time type
func UnixNanoSecondToTime(nanoSecond int64) time.Time {
return time.Unix(0, nanoSecond)
}
//Get the current timestamp by Nano
func GetCurrentTimestampByNano() int64 {
return time.Now().UnixNano()
}
//Get the current timestamp by Mill
func GetCurrentTimestampByMill() int64 {
return time.Now().UnixNano() / 1e6
}
//Get the timestamp at 0 o'clock of the day
func GetCurDayZeroTimestamp() int64 {
timeStr := time.Now().Format("2006-01-02")
t, _ := time.Parse("2006-01-02", timeStr)
return t.Unix() - TimeOffset
}
//Get the timestamp at 12 o'clock on the day
func GetCurDayHalfTimestamp() int64 {
return GetCurDayZeroTimestamp() + HalfOffset
}
//Get the formatted time at 0 o'clock of the day, the format is "2006-01-02_00-00-00"
func GetCurDayZeroTimeFormat() string {
return time.Unix(GetCurDayZeroTimestamp(), 0).Format("2006-01-02_15-04-05")
}
//Get the formatted time at 12 o'clock of the day, the format is "2006-01-02_12-00-00"
func GetCurDayHalfTimeFormat() string {
return time.Unix(GetCurDayZeroTimestamp()+HalfOffset, 0).Format("2006-01-02_15-04-05")
}
func GetTimeStampByFormat(datetime string) string {
timeLayout := "2006-01-02 15:04:05"
loc, _ := time.LoadLocation("Local")
tmp, _ := time.ParseInLocation(timeLayout, datetime, loc)
timestamp := tmp.Unix()
return strconv.FormatInt(timestamp, 10)
}
func TimeStringFormatTimeUnix(timeFormat string, timeSrc string) int64 {
tm, _ := time.Parse(timeFormat, timeSrc)
return tm.Unix()
}