github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/store/sqlstore/session_store.go (about) 1 // Copyright (c) 2015-present Xenia, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package sqlstore 5 6 import ( 7 "fmt" 8 "net/http" 9 "time" 10 11 "github.com/xzl8028/xenia-server/mlog" 12 "github.com/xzl8028/xenia-server/model" 13 "github.com/xzl8028/xenia-server/store" 14 ) 15 16 const ( 17 SESSIONS_CLEANUP_DELAY_MILLISECONDS = 100 18 ) 19 20 type SqlSessionStore struct { 21 SqlStore 22 } 23 24 func NewSqlSessionStore(sqlStore SqlStore) store.SessionStore { 25 us := &SqlSessionStore{sqlStore} 26 27 for _, db := range sqlStore.GetAllConns() { 28 table := db.AddTableWithName(model.Session{}, "Sessions").SetKeys(false, "Id") 29 table.ColMap("Id").SetMaxSize(26) 30 table.ColMap("Token").SetMaxSize(26) 31 table.ColMap("UserId").SetMaxSize(26) 32 table.ColMap("DeviceId").SetMaxSize(512) 33 table.ColMap("Roles").SetMaxSize(64) 34 table.ColMap("Props").SetMaxSize(1000) 35 } 36 37 return us 38 } 39 40 func (me SqlSessionStore) CreateIndexesIfNotExists() { 41 me.CreateIndexIfNotExists("idx_sessions_user_id", "Sessions", "UserId") 42 me.CreateIndexIfNotExists("idx_sessions_token", "Sessions", "Token") 43 me.CreateIndexIfNotExists("idx_sessions_expires_at", "Sessions", "ExpiresAt") 44 me.CreateIndexIfNotExists("idx_sessions_create_at", "Sessions", "CreateAt") 45 me.CreateIndexIfNotExists("idx_sessions_last_activity_at", "Sessions", "LastActivityAt") 46 } 47 48 func (me SqlSessionStore) Save(session *model.Session) (*model.Session, *model.AppError) { 49 if len(session.Id) > 0 { 50 return nil, model.NewAppError("SqlSessionStore.Save", "store.sql_session.save.existing.app_error", nil, "id="+session.Id, http.StatusBadRequest) 51 } 52 53 session.PreSave() 54 55 tcs := make(chan store.StoreResult, 1) 56 go func() { 57 teams, err := me.Team().GetTeamsForUser(session.UserId) 58 tcs <- store.StoreResult{Data: teams, Err: err} 59 close(tcs) 60 }() 61 62 if err := me.GetMaster().Insert(session); err != nil { 63 return nil, model.NewAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+err.Error(), http.StatusInternalServerError) 64 } 65 66 rtcs := <-tcs 67 68 if rtcs.Err != nil { 69 return nil, model.NewAppError("SqlSessionStore.Save", "store.sql_session.save.app_error", nil, "id="+session.Id+", "+rtcs.Err.Error(), http.StatusInternalServerError) 70 } 71 72 tempMembers := rtcs.Data.([]*model.TeamMember) 73 session.TeamMembers = make([]*model.TeamMember, 0, len(tempMembers)) 74 for _, tm := range tempMembers { 75 if tm.DeleteAt == 0 { 76 session.TeamMembers = append(session.TeamMembers, tm) 77 } 78 } 79 80 return session, nil 81 } 82 83 func (me SqlSessionStore) Get(sessionIdOrToken string) (*model.Session, *model.AppError) { 84 var sessions []*model.Session 85 86 if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE Token = :Token OR Id = :Id LIMIT 1", map[string]interface{}{"Token": sessionIdOrToken, "Id": sessionIdOrToken}); err != nil { 87 return nil, model.NewAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+err.Error(), http.StatusInternalServerError) 88 } else if len(sessions) == 0 { 89 return nil, model.NewAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken, http.StatusNotFound) 90 } 91 session := sessions[0] 92 93 tempMembers, err := me.Team().GetTeamsForUser(sessions[0].UserId) 94 if err != nil { 95 return nil, model.NewAppError("SqlSessionStore.Get", "store.sql_session.get.app_error", nil, "sessionIdOrToken="+sessionIdOrToken+", "+err.Error(), http.StatusInternalServerError) 96 } 97 sessions[0].TeamMembers = make([]*model.TeamMember, 0, len(tempMembers)) 98 for _, tm := range tempMembers { 99 if tm.DeleteAt == 0 { 100 sessions[0].TeamMembers = append(sessions[0].TeamMembers, tm) 101 } 102 } 103 return session, nil 104 } 105 106 func (me SqlSessionStore) GetSessions(userId string) ([]*model.Session, *model.AppError) { 107 var sessions []*model.Session 108 109 tcs := make(chan store.StoreResult, 1) 110 go func() { 111 teams, err := me.Team().GetTeamsForUser(userId) 112 tcs <- store.StoreResult{Data: teams, Err: err} 113 close(tcs) 114 }() 115 if _, err := me.GetReplica().Select(&sessions, "SELECT * FROM Sessions WHERE UserId = :UserId ORDER BY LastActivityAt DESC", map[string]interface{}{"UserId": userId}); err != nil { 116 return nil, model.NewAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError) 117 } 118 119 rtcs := <-tcs 120 if rtcs.Err != nil { 121 return nil, model.NewAppError("SqlSessionStore.GetSessions", "store.sql_session.get_sessions.app_error", nil, rtcs.Err.Error(), http.StatusInternalServerError) 122 } 123 124 for _, session := range sessions { 125 tempMembers := rtcs.Data.([]*model.TeamMember) 126 session.TeamMembers = make([]*model.TeamMember, 0, len(tempMembers)) 127 for _, tm := range tempMembers { 128 if tm.DeleteAt == 0 { 129 session.TeamMembers = append(session.TeamMembers, tm) 130 } 131 } 132 } 133 return sessions, nil 134 } 135 136 func (me SqlSessionStore) GetSessionsWithActiveDeviceIds(userId string) ([]*model.Session, *model.AppError) { 137 query := 138 `SELECT * 139 FROM 140 Sessions 141 WHERE 142 UserId = :UserId AND 143 ExpiresAt != 0 AND 144 :ExpiresAt <= ExpiresAt AND 145 DeviceId != ''` 146 147 var sessions []*model.Session 148 149 _, err := me.GetReplica().Select(&sessions, query, map[string]interface{}{"UserId": userId, "ExpiresAt": model.GetMillis()}) 150 if err != nil { 151 return nil, model.NewAppError("SqlSessionStore.GetActiveSessionsWithDeviceIds", "store.sql_session.get_sessions.app_error", nil, err.Error(), http.StatusInternalServerError) 152 } 153 return sessions, nil 154 } 155 156 func (me SqlSessionStore) Remove(sessionIdOrToken string) *model.AppError { 157 _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE Id = :Id Or Token = :Token", map[string]interface{}{"Id": sessionIdOrToken, "Token": sessionIdOrToken}) 158 if err != nil { 159 return model.NewAppError("SqlSessionStore.RemoveSession", "store.sql_session.remove.app_error", nil, "id="+sessionIdOrToken+", err="+err.Error(), http.StatusInternalServerError) 160 } 161 return nil 162 } 163 164 func (me SqlSessionStore) RemoveAllSessions() *model.AppError { 165 _, err := me.GetMaster().Exec("DELETE FROM Sessions") 166 if err != nil { 167 return model.NewAppError("SqlSessionStore.RemoveAllSessions", "store.sql_session.remove_all_sessions_for_team.app_error", nil, err.Error(), http.StatusInternalServerError) 168 } 169 return nil 170 } 171 172 func (me SqlSessionStore) PermanentDeleteSessionsByUser(userId string) *model.AppError { 173 _, err := me.GetMaster().Exec("DELETE FROM Sessions WHERE UserId = :UserId", map[string]interface{}{"UserId": userId}) 174 if err != nil { 175 return model.NewAppError("SqlSessionStore.RemoveAllSessionsForUser", "store.sql_session.permanent_delete_sessions_by_user.app_error", nil, "id="+userId+", err="+err.Error(), http.StatusInternalServerError) 176 } 177 178 return nil 179 } 180 181 func (me SqlSessionStore) UpdateLastActivityAt(sessionId string, time int64) *model.AppError { 182 _, err := me.GetMaster().Exec("UPDATE Sessions SET LastActivityAt = :LastActivityAt WHERE Id = :Id", map[string]interface{}{"LastActivityAt": time, "Id": sessionId}) 183 if err != nil { 184 return model.NewAppError("SqlSessionStore.UpdateLastActivityAt", "store.sql_session.update_last_activity.app_error", nil, "sessionId="+sessionId, http.StatusInternalServerError) 185 } 186 return nil 187 } 188 189 func (me SqlSessionStore) UpdateRoles(userId, roles string) (string, *model.AppError) { 190 query := "UPDATE Sessions SET Roles = :Roles WHERE UserId = :UserId" 191 192 _, err := me.GetMaster().Exec(query, map[string]interface{}{"Roles": roles, "UserId": userId}) 193 if err != nil { 194 return "", model.NewAppError("SqlSessionStore.UpdateRoles", "store.sql_session.update_roles.app_error", nil, "userId="+userId, http.StatusInternalServerError) 195 } 196 return userId, nil 197 } 198 199 func (me SqlSessionStore) UpdateDeviceId(id string, deviceId string, expiresAt int64) (string, *model.AppError) { 200 query := "UPDATE Sessions SET DeviceId = :DeviceId, ExpiresAt = :ExpiresAt WHERE Id = :Id" 201 202 _, err := me.GetMaster().Exec(query, map[string]interface{}{"DeviceId": deviceId, "Id": id, "ExpiresAt": expiresAt}) 203 if err != nil { 204 return "", model.NewAppError("SqlSessionStore.UpdateDeviceId", "store.sql_session.update_device_id.app_error", nil, err.Error(), http.StatusInternalServerError) 205 } 206 return deviceId, nil 207 } 208 209 func (me SqlSessionStore) AnalyticsSessionCount() (int64, *model.AppError) { 210 query := 211 `SELECT 212 COUNT(*) 213 FROM 214 Sessions 215 WHERE ExpiresAt > :Time` 216 count, err := me.GetReplica().SelectInt(query, map[string]interface{}{"Time": model.GetMillis()}) 217 if err != nil { 218 return int64(0), model.NewAppError("SqlSessionStore.AnalyticsSessionCount", "store.sql_session.analytics_session_count.app_error", nil, err.Error(), http.StatusInternalServerError) 219 } 220 return count, nil 221 } 222 223 func (me SqlSessionStore) Cleanup(expiryTime int64, batchSize int64) { 224 mlog.Debug("Cleaning up session store.") 225 226 var query string 227 if me.DriverName() == model.DATABASE_DRIVER_POSTGRES { 228 query = "DELETE FROM Sessions WHERE Id = any (array (SELECT Id FROM Sessions WHERE ExpiresAt != 0 AND :ExpiresAt > ExpiresAt LIMIT :Limit))" 229 } else { 230 query = "DELETE FROM Sessions WHERE ExpiresAt != 0 AND :ExpiresAt > ExpiresAt LIMIT :Limit" 231 } 232 233 var rowsAffected int64 = 1 234 235 for rowsAffected > 0 { 236 if sqlResult, err := me.GetMaster().Exec(query, map[string]interface{}{"ExpiresAt": expiryTime, "Limit": batchSize}); err != nil { 237 mlog.Error(fmt.Sprintf("Unable to cleanup session store. err=%v", err.Error())) 238 return 239 } else { 240 var rowErr error 241 rowsAffected, rowErr = sqlResult.RowsAffected() 242 if rowErr != nil { 243 mlog.Error(fmt.Sprintf("Unable to cleanup session store. err=%v", err.Error())) 244 return 245 } 246 } 247 248 time.Sleep(SESSIONS_CLEANUP_DELAY_MILLISECONDS * time.Millisecond) 249 } 250 }