多租户更改
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
// Package common contains utility methods used by all adapters.
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tinode/chat/server/auth"
|
||||
"github.com/tinode/chat/server/store"
|
||||
t "github.com/tinode/chat/server/store/types"
|
||||
)
|
||||
|
||||
type AuthRecord struct {
|
||||
Unique string `json:"unique" bson:"_id"`
|
||||
UserId string `json:"userid"`
|
||||
Scheme string `json:"scheme"`
|
||||
AuthLvl auth.Level `json:"authLvl"`
|
||||
Secret []byte `json:"secret"`
|
||||
Expires time.Time `json:"expires"`
|
||||
}
|
||||
|
||||
// SelectEarliestUpdatedSubs selects no more than the given number of subscriptions from the
|
||||
// given slice satisfying the query. When the number of subscriptions is greater than the limit,
|
||||
// the subscriptions with the earliest timestamp are selected.
|
||||
func SelectEarliestUpdatedSubs(subs []t.Subscription, opts *t.QueryOpt, maxResults int) []t.Subscription {
|
||||
limit := maxResults
|
||||
ims := time.Time{}
|
||||
if opts != nil {
|
||||
if opts.Limit > 0 && opts.Limit < limit {
|
||||
limit = opts.Limit
|
||||
}
|
||||
if opts.IfModifiedSince != nil {
|
||||
ims = *opts.IfModifiedSince
|
||||
}
|
||||
}
|
||||
|
||||
// No cache management and the number of results is below the limit: return all.
|
||||
if ims.IsZero() && len(subs) <= limit {
|
||||
return subs
|
||||
}
|
||||
|
||||
// Now that we fetched potentially more subscriptions than needed, we got to take those with the oldest modifications.
|
||||
// Sorting in ascending order by modification time.
|
||||
sort.Slice(subs, func(i, j int) bool {
|
||||
return subs[i].LastModified().Before(subs[j].LastModified())
|
||||
})
|
||||
|
||||
if !ims.IsZero() {
|
||||
// Keep only those subscriptions which are newer than ims.
|
||||
at := sort.Search(len(subs), func(i int) bool {
|
||||
return subs[i].LastModified().After(ims)
|
||||
})
|
||||
subs = subs[at:]
|
||||
}
|
||||
// Trim slice at the limit.
|
||||
if len(subs) > limit {
|
||||
subs = subs[:limit]
|
||||
}
|
||||
|
||||
return subs
|
||||
}
|
||||
|
||||
// SelectLatestTime picks the latest update timestamp out of the two.
|
||||
func SelectLatestTime(t1, t2 time.Time) time.Time {
|
||||
if t1.Before(t2) {
|
||||
// Subscription has not changed recently, use user's update timestamp.
|
||||
return t2
|
||||
}
|
||||
|
||||
return t1
|
||||
}
|
||||
|
||||
// RangesToSql converts a slice of ranges to SQL BETWEEN or IN() constraint and arguments.
|
||||
func RangesToSql(in []t.Range) (string, []any) {
|
||||
if len(in) > 1 || in[0].Hi == 0 {
|
||||
var args []any
|
||||
for _, r := range in {
|
||||
if r.Hi == 0 {
|
||||
args = append(args, r.Low)
|
||||
} else {
|
||||
for i := r.Low; i < r.Hi; i++ {
|
||||
args = append(args, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "IN (?" + strings.Repeat(",?", len(args)-1) + ")", args
|
||||
}
|
||||
|
||||
// Optimizing for a special case of single range low..hi.
|
||||
// SQL's BETWEEN is inclusive-inclusive thus decrement Hi by 1.
|
||||
return "BETWEEN ? AND ?", []any{in[0].Low, in[0].Hi - 1}
|
||||
}
|
||||
|
||||
// DisjunctionSql converts a slice of disjunctions to SQL HAVING clause and arguments.
|
||||
func DisjunctionSql(req [][]string, fieldName string) (string, []any) {
|
||||
var args []any
|
||||
counts := make([]string, 0, len(req))
|
||||
for _, reqDisjunction := range req {
|
||||
// At least one of the tags must be present.
|
||||
if len(reqDisjunction) == 0 {
|
||||
continue
|
||||
}
|
||||
counts = append(counts, "COUNT("+fieldName+" IN (?"+strings.Repeat(",?", len(reqDisjunction)-1)+") OR NULL)>=1")
|
||||
for _, tag := range reqDisjunction {
|
||||
args = append(args, tag)
|
||||
}
|
||||
}
|
||||
return "HAVING " + strings.Join(counts, " AND ") + " ", args
|
||||
}
|
||||
|
||||
// FilterFoundTags keeps only those tags in setTags that are present in the index.
|
||||
func FilterFoundTags(setTags t.StringSlice, index map[string]struct{}) []string {
|
||||
foundTags := make([]string, 0, 1)
|
||||
for _, tag := range setTags {
|
||||
if _, ok := index[tag]; ok {
|
||||
foundTags = append(foundTags, tag)
|
||||
}
|
||||
}
|
||||
return foundTags
|
||||
}
|
||||
|
||||
// Convert to JSON before storing to JSON field.
|
||||
func ToJSON(src any) []byte {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
jval, _ := json.Marshal(src)
|
||||
return jval
|
||||
}
|
||||
|
||||
// Deserialize JSON data from DB.
|
||||
func FromJSON(src any) any {
|
||||
if src == nil {
|
||||
return nil
|
||||
}
|
||||
if bb, ok := src.([]byte); ok {
|
||||
var out any
|
||||
json.Unmarshal(bb, &out)
|
||||
return out
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert update to a list of columns and arguments.
|
||||
func UpdateByMap(update map[string]any) (cols []string, args []any) {
|
||||
for col, arg := range update {
|
||||
col = strings.ToLower(col)
|
||||
if col == "public" || col == "trusted" || col == "private" || col == "aux" {
|
||||
arg = ToJSON(arg)
|
||||
}
|
||||
cols = append(cols, col+"=?")
|
||||
args = append(args, arg)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If Tags field is updated, get the tags so tags table cab be updated too.
|
||||
func ExtractTags(update map[string]any) []string {
|
||||
var tags []string
|
||||
|
||||
if val := update["Tags"]; val != nil {
|
||||
tags, _ = val.(t.StringSlice)
|
||||
}
|
||||
|
||||
return []string(tags)
|
||||
}
|
||||
|
||||
// EncodeUidString takes decoded string representation of int64, produce UID.
|
||||
// UIDs are stored as decoded int64 values.
|
||||
func EncodeUidString(str string) t.Uid {
|
||||
unum, _ := strconv.ParseInt(str, 10, 64)
|
||||
return store.EncodeUid(unum)
|
||||
}
|
||||
|
||||
// DecodeUidString takes UID as string, converts it to int64 representation.
|
||||
// UIDs are stored as decoded int64 values.
|
||||
func DecodeUidString(str string) int64 {
|
||||
uid := t.ParseUid(str)
|
||||
return store.DecodeUid(uid)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user