mirror of
https://github.com/tinode/chat.git
synced 2026-05-07 20:12:42 +00:00
minor cleanup in db adapters
This commit is contained in:
+2
-2
@@ -6,7 +6,7 @@ The config file [`tinode.conf`](./server/tinode.conf) contains extensive instruc
|
||||
|
||||
1. Visit the [Releases page](https://github.com/tinode/chat/releases/), choose the latest or otherwise the most suitable release. From the list of binaries download the one for your database and platform. Once the binary is downloaded, unpack it to a directory of your choosing, `cd` to that directory.
|
||||
|
||||
2. Make sure your database is running. Make sure it's configured to accept connections from `localhost`. In case of MySQL, Tinode will try to connect as `root` without the password. In case of PostgreSQL, Tinode will try connect as `postgres` with the password `postgres`. See notes below (_Building from Source_, section 4) on how to configure Tinode to use a different user or a password. MySQL 5.7 or above is required. MySQL 5.6 or below **will not work**. PostgreSQL 13 or above is required. PostgreSQL 12 or below **will not work**.
|
||||
2. Make sure your database is running. Make sure it's configured to accept connections from `localhost`. In case of MySQL, Tinode will try to connect as `root` without the password. In case of PostgreSQL, Tinode will try connect as `postgres` with the password `postgres`. See notes below (_Building from Source_, section 4) on how to configure Tinode to use a different user or a password. MySQL 5.7 or above is required (use InnoDB, not MyISAM storage engine). MySQL 5.6 or below **will not work**. PostgreSQL 13 or above is required. PostgreSQL 12 or below **will not work**.
|
||||
|
||||
3. Run the database initializer `init-db` (or `init-db.exe` on Windows):
|
||||
```
|
||||
@@ -33,7 +33,7 @@ See [instructions](./docker/README.md)
|
||||
2. OPTIONAL only if you intend to modify the code: Install [protobuf](https://developers.google.com/protocol-buffers/) and [gRPC](https://grpc.io/docs/languages/go/quickstart/) including [code generator](https://developers.google.com/protocol-buffers/docs/reference/go-generated) for Go.
|
||||
|
||||
3. Make sure one of the following databases is installed and running:
|
||||
* MySQL 5.7 or above. MySQL 5.6 or below **will not work**.
|
||||
* MySQL 5.7 or above configured with `InnoDB` engine. MySQL 5.6 or below **will not work**.
|
||||
* PostgreSQL 13 or above. PostgreSQL 12 or below **will not work**.
|
||||
* MongoDB 4.4 or above. MongoDB 4.2 and below **will not work**.
|
||||
* RethinkDB (deprecated, support will be dropped in 2027).
|
||||
|
||||
@@ -4,9 +4,11 @@ package common
|
||||
import (
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/tinode/chat/server/store"
|
||||
t "github.com/tinode/chat/server/store/types"
|
||||
)
|
||||
|
||||
@@ -157,3 +159,17 @@ func ExtractTags(update map[string]any) []string {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
+11
-22
@@ -315,7 +315,7 @@ func (a *adapter) CreateDb(reset bool) error {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = tx.Exec("CREATE DATABASE " + a.dbName + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); err != nil {
|
||||
if _, err = tx.Exec("CREATE DATABASE " + a.dbName + " CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1091,7 +1091,7 @@ func (a *adapter) UserGetAll(ids ...t.Uid) ([]t.User, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
user.SetUid(encodeUidString(user.Id))
|
||||
user.SetUid(common.EncodeUidString(user.Id))
|
||||
user.Public = common.FromJSON(user.Public)
|
||||
user.Trusted = common.FromJSON(user.Trusted)
|
||||
|
||||
@@ -1595,7 +1595,7 @@ func (a *adapter) TopicGet(topic string) (*t.Topic, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tt.Owner = encodeUidString(tt.Owner).String()
|
||||
tt.Owner = common.EncodeUidString(tt.Owner).String()
|
||||
tt.Public = common.FromJSON(tt.Public)
|
||||
tt.Trusted = common.FromJSON(tt.Trusted)
|
||||
|
||||
@@ -1798,7 +1798,7 @@ func (a *adapter) TopicsForUser(uid t.Uid, keepDeleted bool, opts *t.QueryOpt) (
|
||||
break
|
||||
}
|
||||
|
||||
joinOn := uid.P2PName(encodeUidString(usr2.Id))
|
||||
joinOn := uid.P2PName(common.EncodeUidString(usr2.Id))
|
||||
if sub, ok := join[joinOn]; ok {
|
||||
sub.UpdatedAt = common.SelectLatestTime(sub.UpdatedAt, usr2.UpdatedAt)
|
||||
sub.SetState(usr2.State)
|
||||
@@ -1897,7 +1897,7 @@ func (a *adapter) UsersForTopic(topic string, keepDeleted bool, opts *t.QueryOpt
|
||||
break
|
||||
}
|
||||
|
||||
sub.User = encodeUidString(sub.User).String()
|
||||
sub.User = common.EncodeUidString(sub.User).String()
|
||||
sub.Private = common.FromJSON(sub.Private)
|
||||
sub.SetPublic(common.FromJSON(public))
|
||||
sub.SetTrusted(common.FromJSON(trusted))
|
||||
@@ -2238,7 +2238,7 @@ func (a *adapter) SubsForTopic(topic string, keepDeleted bool, opts *t.QueryOpt)
|
||||
break
|
||||
}
|
||||
|
||||
ss.User = encodeUidString(ss.User).String()
|
||||
ss.User = common.EncodeUidString(ss.User).String()
|
||||
ss.Private = common.FromJSON(ss.Private)
|
||||
subs = append(subs, ss)
|
||||
}
|
||||
@@ -2599,7 +2599,7 @@ func (a *adapter) MessageGetAll(topic string, forUser t.Uid, opts *t.QueryOpt) (
|
||||
if err = rows.StructScan(&msg); err != nil {
|
||||
break
|
||||
}
|
||||
msg.From = encodeUidString(msg.From).String()
|
||||
msg.From = common.EncodeUidString(msg.From).String()
|
||||
msg.Content = common.FromJSON(msg.Content)
|
||||
msgs = append(msgs, msg)
|
||||
}
|
||||
@@ -2771,7 +2771,7 @@ func messageDeleteList(tx *sqlx.Tx, topic string, toDel *t.DelMessage) error {
|
||||
return err
|
||||
}
|
||||
|
||||
forUser := decodeUidString(toDel.DeletedFor)
|
||||
forUser := common.DecodeUidString(toDel.DeletedFor)
|
||||
for _, rng := range delRanges {
|
||||
if rng.Hi == 0 {
|
||||
// Dellog must contain valid Low and *Hi*.
|
||||
@@ -2971,7 +2971,7 @@ func (a *adapter) CredUpsert(cred *t.Credential) (bool, error) {
|
||||
}()
|
||||
|
||||
now := t.TimeNow()
|
||||
userId := decodeUidString(cred.User)
|
||||
userId := common.DecodeUidString(cred.User)
|
||||
|
||||
// Enforce uniqueness: if credential is confirmed, "method:value" must be unique.
|
||||
// if credential is not yet confirmed, "userid:method:value" is unique.
|
||||
@@ -3277,8 +3277,8 @@ func (a *adapter) FileGet(fid string) (*t.FileDef, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fd.Id = encodeUidString(fd.Id).String()
|
||||
fd.User = encodeUidString(fd.User).String()
|
||||
fd.Id = common.EncodeUidString(fd.Id).String()
|
||||
fd.User = common.EncodeUidString(fd.User).String()
|
||||
|
||||
return &fd, nil
|
||||
|
||||
@@ -3522,17 +3522,6 @@ func isMissingDb(err error) bool {
|
||||
return ok && myerr.Number == 1049
|
||||
}
|
||||
|
||||
// UIDs are stored as decoded int64 values. Take decoded string representation of int64, produce UID.
|
||||
func encodeUidString(str string) t.Uid {
|
||||
unum, _ := strconv.ParseInt(str, 10, 64)
|
||||
return store.EncodeUid(unum)
|
||||
}
|
||||
|
||||
func decodeUidString(str string) int64 {
|
||||
uid := t.ParseUid(str)
|
||||
return store.DecodeUid(uid)
|
||||
}
|
||||
|
||||
func init() {
|
||||
store.RegisterAdapter(&adapter{})
|
||||
}
|
||||
|
||||
@@ -2278,7 +2278,7 @@ func (a *adapter) SubsDelForUser(user t.Uid, hard bool) error {
|
||||
|
||||
}
|
||||
|
||||
// Find returns a list of users and group topics which match teh given tags, such as "email:jdoe@example.com" or "tel:+18003287448".
|
||||
// Find returns a list of users and group topics which match the given tags, such as "email:jdoe@example.com" or "tel:+18003287448".
|
||||
func (a *adapter) Find(caller, promoPrefix string, req [][]string, opt []string, activeOnly bool) ([]t.Subscription, error) {
|
||||
index := make(map[string]struct{})
|
||||
var args []any
|
||||
@@ -2693,7 +2693,7 @@ func messageDeleteList(ctx context.Context, tx pgx.Tx, topic string, toDel *t.De
|
||||
// Now make log entries. Needed for both hard- and soft-deleting.
|
||||
|
||||
// Prepare statement is not needed because the driver prepares the statement on first use then caches it.
|
||||
forUser := decodeUidString(toDel.DeletedFor)
|
||||
forUser := common.DecodeUidString(toDel.DeletedFor)
|
||||
for _, rng := range toDel.SeqIdRanges {
|
||||
if rng.Hi == 0 {
|
||||
// Dellog must contain valid Low and *Hi*.
|
||||
@@ -2895,7 +2895,7 @@ func (a *adapter) CredUpsert(cred *t.Credential) (bool, error) {
|
||||
}()
|
||||
|
||||
now := t.TimeNow()
|
||||
userId := decodeUidString(cred.User)
|
||||
userId := common.DecodeUidString(cred.User)
|
||||
|
||||
// Enforce uniqueness: if credential is confirmed, "method:value" must be unique.
|
||||
// if credential is not yet confirmed, "userid:method:value" is unique.
|
||||
@@ -3466,18 +3466,7 @@ func isMissingDb(err error) bool {
|
||||
return strings.Contains(msg, "SQLSTATE 3D000")
|
||||
}
|
||||
|
||||
// UIDs are stored as decoded int64 values. Take decoded string representation of int64, produce UID.
|
||||
func encodeUidString(str string) t.Uid {
|
||||
unum, _ := strconv.ParseInt(str, 10, 64)
|
||||
return store.EncodeUid(unum)
|
||||
}
|
||||
|
||||
func decodeUidString(str string) int64 {
|
||||
uid := t.ParseUid(str)
|
||||
return store.DecodeUid(uid)
|
||||
}
|
||||
|
||||
// Converting a structure with data to enter a connection string
|
||||
// setConnStr converts a config structure to a DSN connection string.
|
||||
func setConnStr(c configType) (string, error) {
|
||||
// Default to disable SSL mode.
|
||||
sslMode := "disable"
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
"slices"
|
||||
)
|
||||
|
||||
// StoreError satisfies Error interface but allows constant values for
|
||||
|
||||
+4
-4
@@ -289,16 +289,16 @@
|
||||
"Net": "tcp",
|
||||
"Addr": "localhost",
|
||||
"DBName": "tinode",
|
||||
// The 'collation=utf8mb4_unicode_ci' is optional but highly recommended for
|
||||
// emoji and certain CJK characters.
|
||||
"Collation": "utf8mb4_unicode_ci",
|
||||
// The 'collation=utf8mb4_0900_ai_ci' is default in MySQL 8.0 and above. It is optional but highly
|
||||
// recommended for emoji and certain CJK characters in earlier versions of MySQL.
|
||||
"Collation": "utf8mb4_0900_ai_ci",
|
||||
// Parse time values to time.Time. Required.
|
||||
"ParseTime": true,
|
||||
|
||||
// DSN: alternative way of specifying database configuration, passed unchanged
|
||||
// to MySQL driver. See https://github.com/go-sql-driver/mysql#dsn-data-source-name for syntax.
|
||||
// DSN may optionally start with mysql://
|
||||
// "dsn": "root@tcp(localhost)/tinode?parseTime=true&collation=utf8mb4_unicode_ci",
|
||||
// "dsn": "root@tcp(localhost)/tinode?parseTime=true&collation=utf8mb4_0900_ai_ci",
|
||||
|
||||
// MySQL connection pool settings.
|
||||
// Maximum number of open connections to the database. Default: 0 (unlimited).
|
||||
|
||||
+1
-1
@@ -502,7 +502,7 @@ func validateTag(tag string) (string, string) {
|
||||
|
||||
// hasDuplicateNamespaceTags checks for duplication of unique NS tags.
|
||||
// Each namespace can have only one tag. This does not prevent tags from
|
||||
// being duplicate accross requests, just saves an extra DB call.
|
||||
// being duplicate across requests, just saves an extra DB call.
|
||||
func hasDuplicateNamespaceTags(src []string, uniqueNS string) bool {
|
||||
found := map[string]bool{}
|
||||
for _, tag := range src {
|
||||
|
||||
@@ -275,9 +275,9 @@ func (v *validator) Request(user t.Uid, email, lang, resp string, tmpToken []byt
|
||||
var template *textt.Template
|
||||
if v.langMatcher != nil {
|
||||
// Find the template for the requested language.
|
||||
// Make sure the language tag is standartized. Matcher is a bit dumber than Parse().
|
||||
// Make sure the language tag is standardized. Matcher is a bit dumber than Parse().
|
||||
normalized, _ := i18n.Parse(lang)
|
||||
// The matched tag is usualy not in the list of available languages (e.g. es_ES -> es-u-rg-eszzzz).
|
||||
// The matched tag is usually not in the list of available languages (e.g. es_ES -> es-u-rg-eszzzz).
|
||||
// Use index to find the template instead of tag.
|
||||
_, idx := i18n.MatchStrings(v.langMatcher, normalized.String())
|
||||
template = v.validationTempl[idx]
|
||||
|
||||
Reference in New Issue
Block a user