mirror of
https://github.com/anyproto/anytype-heart.git
synced 2025-06-07 21:37:04 +09:00
GO-4414 Allow user to choose a primary language (#2172)
This commit is contained in:
parent
b243f1f4e2
commit
19e2abb130
25 changed files with 1701 additions and 1375 deletions
|
@ -136,8 +136,8 @@ func BootstrapConfig(newAccount bool, isStaging bool) *config.Config {
|
|||
)
|
||||
}
|
||||
|
||||
func BootstrapWallet(rootPath string, derivationResult crypto.DerivationResult) wallet.Wallet {
|
||||
return wallet.NewWithAccountRepo(rootPath, derivationResult)
|
||||
func BootstrapWallet(rootPath string, derivationResult crypto.DerivationResult, lang string) wallet.Wallet {
|
||||
return wallet.NewWithAccountRepo(rootPath, derivationResult, lang)
|
||||
}
|
||||
|
||||
func StartNewApp(ctx context.Context, clientWithVersion string, components ...app.Component) (a *app.App, err error) {
|
||||
|
|
|
@ -62,7 +62,7 @@ func (s *Service) AccountCreate(ctx context.Context, req *pb.RpcAccountCreateReq
|
|||
}
|
||||
comps := []app.Component{
|
||||
cfg,
|
||||
anytype.BootstrapWallet(s.rootPath, derivationResult),
|
||||
anytype.BootstrapWallet(s.rootPath, derivationResult, s.fulltextPrimaryLanguage),
|
||||
s.eventSender,
|
||||
}
|
||||
|
||||
|
|
|
@ -87,6 +87,7 @@ func (s *Service) RecoverFromLegacy(req *pb.RpcAccountRecoverFromLegacyExportReq
|
|||
return RecoverFromLegacyResponse{}, ErrAccountMismatch
|
||||
}
|
||||
s.rootPath = req.RootPath
|
||||
s.fulltextPrimaryLanguage = req.FulltextPrimaryLanguage
|
||||
err = os.MkdirAll(s.rootPath, 0700)
|
||||
if err != nil {
|
||||
return RecoverFromLegacyResponse{}, anyerror.CleanupError(err)
|
||||
|
@ -134,7 +135,7 @@ func (s *Service) RecoverFromLegacy(req *pb.RpcAccountRecoverFromLegacyExportReq
|
|||
func (s *Service) startApp(cfg *config.Config, derivationResult crypto.DerivationResult) error {
|
||||
comps := []app.Component{
|
||||
cfg,
|
||||
anytype.BootstrapWallet(s.rootPath, derivationResult),
|
||||
anytype.BootstrapWallet(s.rootPath, derivationResult, s.fulltextPrimaryLanguage),
|
||||
s.eventSender,
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ func (s *Service) AccountSelect(ctx context.Context, req *pb.RpcAccountSelectReq
|
|||
if req.Id == "" {
|
||||
return nil, ErrEmptyAccountID
|
||||
}
|
||||
curMigration := s.migrationManager.getOrCreateMigration(req.RootPath, req.Id)
|
||||
curMigration := s.migrationManager.getOrCreateMigration(req.RootPath, req.Id, req.FulltextPrimaryLanguage)
|
||||
if !curMigration.successful() {
|
||||
return nil, ErrAccountStoreIsNotMigrated
|
||||
}
|
||||
|
@ -82,16 +82,30 @@ func (s *Service) AccountSelect(ctx context.Context, req *pb.RpcAccountSelectReq
|
|||
}
|
||||
metrics.Service.SetWorkingDir(req.RootPath, req.Id)
|
||||
|
||||
return s.start(ctx, req.Id, req.RootPath, req.DisableLocalNetworkSync, req.JsonApiListenAddr, req.PreferYamuxTransport, req.NetworkMode, req.NetworkCustomConfigFilePath)
|
||||
return s.start(ctx, req.Id, req.RootPath, req.DisableLocalNetworkSync, req.JsonApiListenAddr,
|
||||
req.PreferYamuxTransport, req.NetworkMode, req.NetworkCustomConfigFilePath, req.FulltextPrimaryLanguage)
|
||||
}
|
||||
|
||||
func (s *Service) start(ctx context.Context, id string, rootPath string, disableLocalNetworkSync bool, jsonApiListenAddr string, preferYamux bool, networkMode pb.RpcAccountNetworkMode, networkConfigFilePath string) (*model.Account, error) {
|
||||
func (s *Service) start(
|
||||
ctx context.Context,
|
||||
id string,
|
||||
rootPath string,
|
||||
disableLocalNetworkSync bool,
|
||||
jsonApiListenAddr string,
|
||||
preferYamux bool,
|
||||
networkMode pb.RpcAccountNetworkMode,
|
||||
networkConfigFilePath string,
|
||||
lang string,
|
||||
) (*model.Account, error) {
|
||||
ctx, task := trace2.NewTask(ctx, "application.start")
|
||||
defer task.End()
|
||||
|
||||
if rootPath != "" {
|
||||
s.rootPath = rootPath
|
||||
}
|
||||
if lang != "" {
|
||||
s.fulltextPrimaryLanguage = lang
|
||||
}
|
||||
if s.mnemonic == "" {
|
||||
return nil, ErrNoMnemonicProvided
|
||||
}
|
||||
|
@ -129,7 +143,7 @@ func (s *Service) start(ctx context.Context, id string, rootPath string, disable
|
|||
}
|
||||
comps := []app.Component{
|
||||
cfg,
|
||||
anytype.BootstrapWallet(s.rootPath, res),
|
||||
anytype.BootstrapWallet(s.rootPath, res, s.fulltextPrimaryLanguage),
|
||||
s.eventSender,
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ func (s *Service) AccountChangeNetworkConfigAndRestart(ctx context.Context, req
|
|||
}
|
||||
|
||||
rootPath := s.app.MustComponent(walletComp.CName).(walletComp.Wallet).RootPath()
|
||||
lang := s.app.MustComponent(walletComp.CName).(walletComp.Wallet).FtsPrimaryLang()
|
||||
accountId := s.app.MustComponent(walletComp.CName).(walletComp.Wallet).GetAccountPrivkey().GetPublic().Account()
|
||||
conf := s.app.MustComponent(config.CName).(*config.Config)
|
||||
|
||||
|
@ -89,7 +90,8 @@ func (s *Service) AccountChangeNetworkConfigAndRestart(ctx context.Context, req
|
|||
return ErrFailedToStopApplication
|
||||
}
|
||||
|
||||
_, err = s.start(ctx, accountId, rootPath, conf.DontStartLocalNetworkSyncAutomatically, conf.JsonApiListenAddr, conf.PeferYamuxTransport, req.NetworkMode, req.NetworkCustomConfigFilePath)
|
||||
_, err = s.start(ctx, accountId, rootPath, conf.DontStartLocalNetworkSyncAutomatically, conf.JsonApiListenAddr,
|
||||
conf.PeferYamuxTransport, req.NetworkMode, req.NetworkCustomConfigFilePath, lang)
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ func (s *Service) AccountMigrate(ctx context.Context, req *pb.RpcAccountMigrateR
|
|||
if s.rootPath == "" {
|
||||
s.rootPath = req.RootPath
|
||||
}
|
||||
return s.migrationManager.getOrCreateMigration(req.RootPath, req.Id).wait()
|
||||
return s.migrationManager.getOrCreateMigration(req.RootPath, req.Id, req.FulltextPrimaryLanguage).wait()
|
||||
}
|
||||
|
||||
func (s *Service) AccountMigrateCancel(ctx context.Context, req *pb.RpcAccountMigrateCancelRequest) error {
|
||||
|
@ -37,7 +37,7 @@ func (s *Service) AccountMigrateCancel(ctx context.Context, req *pb.RpcAccountMi
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) migrate(ctx context.Context, id string) error {
|
||||
func (s *Service) migrate(ctx context.Context, id, lang string) error {
|
||||
res, err := core.WalletAccountAt(s.mnemonic, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -53,7 +53,7 @@ func (s *Service) migrate(ctx context.Context, id string) error {
|
|||
cfg.DisableNetworkIdCheck = true
|
||||
comps := []app.Component{
|
||||
cfg,
|
||||
anytype.BootstrapWallet(s.rootPath, res),
|
||||
anytype.BootstrapWallet(s.rootPath, res, lang),
|
||||
s.eventSender,
|
||||
}
|
||||
a := &app.App{}
|
||||
|
@ -75,21 +75,23 @@ type migration struct {
|
|||
err error
|
||||
id string
|
||||
done chan struct{}
|
||||
lang string
|
||||
}
|
||||
|
||||
func newMigration(m *migrationManager, id string) *migration {
|
||||
func newMigration(m *migrationManager, id, lang string) *migration {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
return &migration{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
done: make(chan struct{}),
|
||||
id: id,
|
||||
lang: lang,
|
||||
manager: m,
|
||||
}
|
||||
}
|
||||
|
||||
func newSuccessfulMigration(manager *migrationManager, id string) *migration {
|
||||
m := newMigration(manager, id)
|
||||
func newSuccessfulMigration(manager *migrationManager, id, lang string) *migration {
|
||||
m := newMigration(manager, id, lang)
|
||||
m.setFinished(nil, false)
|
||||
return m
|
||||
}
|
||||
|
@ -127,7 +129,7 @@ func (m *migration) wait() error {
|
|||
return m.err
|
||||
}
|
||||
m.mx.Unlock()
|
||||
err := m.manager.service.migrate(m.ctx, m.id)
|
||||
err := m.manager.service.migrate(m.ctx, m.id, m.lang)
|
||||
if err != nil {
|
||||
m.setFinished(err, true)
|
||||
return err
|
||||
|
@ -184,7 +186,7 @@ func (m *migrationManager) isRunning() bool {
|
|||
return m.runningMigration != ""
|
||||
}
|
||||
|
||||
func (m *migrationManager) getOrCreateMigration(rootPath, id string) *migration {
|
||||
func (m *migrationManager) getOrCreateMigration(rootPath, id, lang string) *migration {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
if m.migrations == nil {
|
||||
|
@ -194,14 +196,14 @@ func (m *migrationManager) getOrCreateMigration(rootPath, id string) *migration
|
|||
sqlitePath := filepath.Join(rootPath, id, config.SpaceStoreSqlitePath)
|
||||
baderPath := filepath.Join(rootPath, id, config.SpaceStoreBadgerPath)
|
||||
if anyPathExists([]string{sqlitePath, baderPath}) {
|
||||
m.migrations[id] = newMigration(m, id)
|
||||
m.migrations[id] = newMigration(m, id, lang)
|
||||
} else {
|
||||
m.migrations[id] = newSuccessfulMigration(m, id)
|
||||
m.migrations[id] = newSuccessfulMigration(m, id, lang)
|
||||
}
|
||||
}
|
||||
if m.migrations[id].finished() && !m.migrations[id].successful() {
|
||||
// resetting migration
|
||||
m.migrations[id] = newMigration(m, id)
|
||||
m.migrations[id] = newMigration(m, id, lang)
|
||||
}
|
||||
return m.migrations[id]
|
||||
}
|
||||
|
|
|
@ -25,12 +25,13 @@ type Service struct {
|
|||
// memoized private key derived from mnemonic, used for signing session tokens
|
||||
sessionSigningKey []byte
|
||||
|
||||
rootPath string
|
||||
clientWithVersion string
|
||||
eventSender event.Sender
|
||||
sessions session.Service
|
||||
traceRecorder *traceRecorder
|
||||
migrationManager *migrationManager
|
||||
rootPath string
|
||||
fulltextPrimaryLanguage string
|
||||
clientWithVersion string
|
||||
eventSender event.Sender
|
||||
sessions session.Service
|
||||
traceRecorder *traceRecorder
|
||||
migrationManager *migrationManager
|
||||
|
||||
appAccountStartInProcessCancel context.CancelFunc
|
||||
appAccountStartInProcessCancelMutex sync.Mutex
|
||||
|
|
|
@ -17,6 +17,7 @@ func (s *Service) WalletCreate(req *pb.RpcWalletCreateRequest) (string, error) {
|
|||
defer s.lock.Unlock()
|
||||
|
||||
s.rootPath = req.RootPath
|
||||
s.fulltextPrimaryLanguage = req.FulltextPrimaryLanguage
|
||||
|
||||
err := os.MkdirAll(s.rootPath, 0700)
|
||||
if err != nil {
|
||||
|
|
|
@ -32,5 +32,6 @@ func (s *Service) WalletRecover(req *pb.RpcWalletRecoverRequest) error {
|
|||
return err
|
||||
}
|
||||
s.rootPath = req.RootPath
|
||||
s.fulltextPrimaryLanguage = req.FulltextPrimaryLanguage
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -73,6 +73,51 @@ func (_c *MockWallet_Account_Call) RunAndReturn(run func() *accountdata.AccountK
|
|||
return _c
|
||||
}
|
||||
|
||||
// FtsPrimaryLang provides a mock function with given fields:
|
||||
func (_m *MockWallet) FtsPrimaryLang() string {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for FtsPrimaryLang")
|
||||
}
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func() string); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// MockWallet_FtsPrimaryLang_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'FtsPrimaryLang'
|
||||
type MockWallet_FtsPrimaryLang_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// FtsPrimaryLang is a helper method to define mock.On call
|
||||
func (_e *MockWallet_Expecter) FtsPrimaryLang() *MockWallet_FtsPrimaryLang_Call {
|
||||
return &MockWallet_FtsPrimaryLang_Call{Call: _e.mock.On("FtsPrimaryLang")}
|
||||
}
|
||||
|
||||
func (_c *MockWallet_FtsPrimaryLang_Call) Run(run func()) *MockWallet_FtsPrimaryLang_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWallet_FtsPrimaryLang_Call) Return(_a0 string) *MockWallet_FtsPrimaryLang_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockWallet_FtsPrimaryLang_Call) RunAndReturn(run func() string) *MockWallet_FtsPrimaryLang_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetAccountEthAddress provides a mock function with given fields:
|
||||
func (_m *MockWallet) GetAccountEthAddress() wallet.EthAddress {
|
||||
ret := _m.Called()
|
||||
|
|
|
@ -29,6 +29,7 @@ type EthAddress = common.Address
|
|||
type wallet struct {
|
||||
rootPath string
|
||||
repoPath string // other components will init their files/dirs inside
|
||||
lang string
|
||||
deviceKeyPath string
|
||||
|
||||
accountKey crypto.PrivKey
|
||||
|
@ -117,6 +118,10 @@ func (r *wallet) RepoPath() string {
|
|||
return r.repoPath
|
||||
}
|
||||
|
||||
func (r *wallet) FtsPrimaryLang() string {
|
||||
return r.lang
|
||||
}
|
||||
|
||||
func (r *wallet) RootPath() string {
|
||||
return r.rootPath
|
||||
}
|
||||
|
@ -129,12 +134,13 @@ func (r *wallet) Account() *accountdata.AccountKeys {
|
|||
return r.accountData
|
||||
}
|
||||
|
||||
func NewWithAccountRepo(rootPath string, derivationResult crypto.DerivationResult) Wallet {
|
||||
func NewWithAccountRepo(rootPath string, derivationResult crypto.DerivationResult, lang string) Wallet {
|
||||
accountId := derivationResult.Identity.GetPublic().Account()
|
||||
repoPath := filepath.Join(rootPath, accountId)
|
||||
return &wallet{
|
||||
rootPath: rootPath,
|
||||
repoPath: repoPath,
|
||||
lang: lang,
|
||||
masterKey: derivationResult.MasterKey,
|
||||
oldAccountKey: derivationResult.OldAccountKey,
|
||||
accountKey: derivationResult.Identity,
|
||||
|
@ -160,6 +166,7 @@ func NewWithRepoPathAndKeys(repoPath string, accountKeypair, deviceKeypair crypt
|
|||
type Wallet interface {
|
||||
RootPath() string
|
||||
RepoPath() string
|
||||
FtsPrimaryLang() string
|
||||
GetAccountPrivkey() crypto.PrivKey
|
||||
GetDevicePrivkey() crypto.PrivKey
|
||||
GetOldAccountKey() crypto.PrivKey
|
||||
|
|
|
@ -13,8 +13,11 @@ make download-tantivy-all-force
|
|||
|
||||
#### Mac
|
||||
As of 16.01.23 last protobuf version (21.12) broke the JS plugin support, so you can use the v3 branch:
|
||||
Make sure you've removed protobuf
|
||||
```
|
||||
brew remove protobuf --ignore-dependencies
|
||||
brew install protobuf@3
|
||||
brew link --force --overwrite protobuf@3
|
||||
```
|
||||
|
||||
To generate Swift protobuf:
|
||||
|
|
|
@ -3510,6 +3510,7 @@ TODO: Remove this request if we do not need it, GO-1926
|
|||
| ----- | ---- | ----- | ----------- |
|
||||
| id | [string](#string) | | Id of a selected account |
|
||||
| rootPath | [string](#string) | | |
|
||||
| fulltextPrimaryLanguage | [string](#string) | | optional, default fts language |
|
||||
|
||||
|
||||
|
||||
|
@ -3732,6 +3733,7 @@ Middleware-to-front-end response to an account recover request, that can contain
|
|||
| path | [string](#string) | | |
|
||||
| rootPath | [string](#string) | | |
|
||||
| icon | [int64](#int64) | | |
|
||||
| fulltextPrimaryLanguage | [string](#string) | | optional, default fts language |
|
||||
|
||||
|
||||
|
||||
|
@ -3849,6 +3851,7 @@ User can select an account from those, that came with an AccountAdd events
|
|||
| networkCustomConfigFilePath | [string](#string) | | config path for the custom network mode |
|
||||
| preferYamuxTransport | [bool](#bool) | | optional, default is false, recommended in case of problems with QUIC transport |
|
||||
| jsonApiListenAddr | [string](#string) | | optional, if empty json api will not be started; 127.0.0.1:31009 should be the default one |
|
||||
| fulltextPrimaryLanguage | [string](#string) | | optional, default fts language |
|
||||
|
||||
|
||||
|
||||
|
@ -20297,6 +20300,7 @@ Front-end-to-middleware request to create a new wallet
|
|||
| Field | Type | Label | Description |
|
||||
| ----- | ---- | ----- | ----------- |
|
||||
| rootPath | [string](#string) | | Path to a wallet directory |
|
||||
| fulltextPrimaryLanguage | [string](#string) | | optional, default fts language |
|
||||
|
||||
|
||||
|
||||
|
@ -20415,6 +20419,7 @@ Front end to middleware request-to-recover-a wallet with this mnemonic and a roo
|
|||
| ----- | ---- | ----- | ----------- |
|
||||
| rootPath | [string](#string) | | Path to a wallet directory |
|
||||
| mnemonic | [string](#string) | | Mnemonic of a wallet to recover |
|
||||
| fulltextPrimaryLanguage | [string](#string) | | optional, default fts language |
|
||||
|
||||
|
||||
|
||||
|
|
4
go.mod
4
go.mod
|
@ -15,7 +15,7 @@ require (
|
|||
github.com/anyproto/go-slip10 v1.0.0
|
||||
github.com/anyproto/lexid v0.0.4
|
||||
github.com/anyproto/protobuf v1.3.3-0.20240814124528-72b8c7e0e0f5
|
||||
github.com/anyproto/tantivy-go v0.3.1
|
||||
github.com/anyproto/tantivy-go v1.0.1
|
||||
github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
|
||||
github.com/avast/retry-go/v4 v4.6.0
|
||||
github.com/chai2010/webp v1.1.2-0.20240612091223-aa1b379218b7
|
||||
|
@ -105,7 +105,7 @@ require (
|
|||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa
|
||||
golang.org/x/image v0.24.0
|
||||
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f
|
||||
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/oauth2 v0.26.0
|
||||
golang.org/x/sys v0.30.0
|
||||
|
|
8
go.sum
8
go.sum
|
@ -116,8 +116,8 @@ github.com/anyproto/protobuf v1.3.3-0.20240814124528-72b8c7e0e0f5 h1:aY7tBzQ+z8H
|
|||
github.com/anyproto/protobuf v1.3.3-0.20240814124528-72b8c7e0e0f5/go.mod h1:5+PHE01DgsDPkralb8MYmGg2sPQahsqEJ9ue7ciDHKg=
|
||||
github.com/anyproto/ristretto v0.1.2-0.20240221153107-2b23839cc50c h1:GicoaTUyB2mtCIl3YMrO0OzysqRT5GA4vuvDsqEkhSM=
|
||||
github.com/anyproto/ristretto v0.1.2-0.20240221153107-2b23839cc50c/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA=
|
||||
github.com/anyproto/tantivy-go v0.3.1 h1:59XePWnHlaTOgw1jVqpKD7oyZa8nwY5+U9UKnt0HHZU=
|
||||
github.com/anyproto/tantivy-go v0.3.1/go.mod h1:7hhkPpyTq7+W1dx9Dcva4bsg4TLHq9xqmmYLCwqDq/k=
|
||||
github.com/anyproto/tantivy-go v1.0.1 h1:Uc9WqwGEDsVUEwRgSg4nmhoW20GjMUBKRz5FYw4r+ns=
|
||||
github.com/anyproto/tantivy-go v1.0.1/go.mod h1:LtipOpRjGtcYMGcop6gQN7rVl1Pc6BlIs9BTMqeWMsk=
|
||||
github.com/anyproto/zeroconf/v2 v2.2.1-0.20240228113933-f90a5cc4439d h1:5bj7nX/AS8sxGpTIrapE7PC4oPlhkHMwMqXlJbUHBlg=
|
||||
github.com/anyproto/zeroconf/v2 v2.2.1-0.20240228113933-f90a5cc4439d/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
|
@ -1227,8 +1227,8 @@ golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPI
|
|||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f h1:23H/YlmTHfmmvpZ+ajKZL0qLz0+IwFOIqQA0mQbmLeM=
|
||||
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f/go.mod h1:UbSUP4uu/C9hw9R2CkojhXlAxvayHjBdU9aRvE+c1To=
|
||||
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3 h1:0V/7Y1FEaFdAzb9DkVDh4QFp4vL4yYCiJ5cjk80lZyA=
|
||||
golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3/go.mod h1:j5VYNgQ6lZYZlzHFjdgS2UeqRSZunDk+/zXVTAIA3z4=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
|
|
|
@ -41,4 +41,4 @@ setup-protoc-jsweb:
|
|||
mv deps/grpc-web/javascript/net/grpc/web/generator/protoc-gen-grpc-web deps/protoc-gen-grpc-web
|
||||
@rm -rf deps/grpc-web
|
||||
|
||||
setup-protoc: setup-protoc-go setup-protoc-jsweb
|
||||
setup-protoc: setup-protoc-go setup-protoc-jsweb
|
2784
pb/commands.pb.go
2784
pb/commands.pb.go
File diff suppressed because it is too large
Load diff
|
@ -543,6 +543,7 @@ message Rpc {
|
|||
message Request {
|
||||
option (no_auth) = true;
|
||||
string rootPath = 1; // Path to a wallet directory
|
||||
string fulltextPrimaryLanguage = 2; // optional, default fts language
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -577,6 +578,7 @@ message Rpc {
|
|||
|
||||
string rootPath = 1; // Path to a wallet directory
|
||||
string mnemonic = 2; // Mnemonic of a wallet to recover
|
||||
string fulltextPrimaryLanguage = 3; // optional, default fts language
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -817,6 +819,7 @@ message Rpc {
|
|||
option (no_auth) = true;
|
||||
string id = 1; // Id of a selected account
|
||||
string rootPath = 2;
|
||||
string fulltextPrimaryLanguage = 3; // optional, default fts language
|
||||
}
|
||||
|
||||
message Response {
|
||||
|
@ -874,6 +877,7 @@ message Rpc {
|
|||
string networkCustomConfigFilePath = 5; // config path for the custom network mode
|
||||
bool preferYamuxTransport = 6; // optional, default is false, recommended in case of problems with QUIC transport
|
||||
string jsonApiListenAddr = 7; // optional, if empty json api will not be started; 127.0.0.1:31009 should be the default one
|
||||
string fulltextPrimaryLanguage = 8; // optional, default fts language
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1042,6 +1046,7 @@ message Rpc {
|
|||
string path = 1;
|
||||
string rootPath = 2;
|
||||
int64 icon = 3;
|
||||
string fulltextPrimaryLanguage = 4; // optional, default fts language
|
||||
}
|
||||
|
||||
message Response {
|
||||
|
|
|
@ -41,7 +41,7 @@ func (f *ftSearchTantivy) Iterate(objectId string, fields []string, shouldContin
|
|||
defer f.parserPool.Put(parser)
|
||||
searchResult, err := tantivy.GetSearchResults(
|
||||
result,
|
||||
f.schema,
|
||||
f.index,
|
||||
func(json string) (*DocumentMatch, error) {
|
||||
value, err := parser.Parse(json)
|
||||
if err != nil {
|
||||
|
@ -114,37 +114,22 @@ func (f *ftIndexBatcherTantivy) UpdateDoc(searchDoc SearchDoc) error {
|
|||
return fmt.Errorf("failed to create document")
|
||||
}
|
||||
|
||||
err = doc.AddField(fieldId, searchDoc.Id, f.index)
|
||||
err = doc.AddFields(searchDoc.Id, f.index, fieldId, fieldIdRaw)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = doc.AddField(fieldIdRaw, searchDoc.Id, f.index)
|
||||
err = doc.AddField(searchDoc.SpaceId, f.index, fieldSpace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = doc.AddField(fieldSpace, searchDoc.SpaceId, f.index)
|
||||
err = doc.AddFields(searchDoc.Title, f.index, fieldTitle, fieldTitleZh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = doc.AddField(fieldTitle, searchDoc.Title, f.index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = doc.AddField(fieldTitleZh, searchDoc.Title, f.index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = doc.AddField(fieldText, searchDoc.Text, f.index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = doc.AddField(fieldTextZh, searchDoc.Text, f.index)
|
||||
err = doc.AddFields(searchDoc.Text, f.index, fieldText, fieldTextZh)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
|
@ -91,21 +91,15 @@ type DocumentMatch struct {
|
|||
Fields map[string]any
|
||||
}
|
||||
|
||||
var specialChars = map[rune]struct{}{
|
||||
'+': {}, '^': {}, '`': {}, ':': {}, '{': {},
|
||||
'}': {}, '"': {}, '[': {}, ']': {}, '(': {},
|
||||
')': {}, '~': {}, '!': {}, '\\': {}, '*': {},
|
||||
}
|
||||
|
||||
type ftSearchTantivy struct {
|
||||
rootPath string
|
||||
ftsPath string
|
||||
builderId string
|
||||
index *tantivy.TantivyContext
|
||||
schema *tantivy.Schema
|
||||
parserPool *fastjson.ParserPool
|
||||
mu sync.Mutex
|
||||
blevePath string
|
||||
lang tantivy.Language
|
||||
}
|
||||
|
||||
func TantivyNew() FTSearch {
|
||||
|
@ -144,6 +138,7 @@ func (f *ftSearchTantivy) DeleteObject(objectId string) error {
|
|||
|
||||
func (f *ftSearchTantivy) Init(a *app.App) error {
|
||||
repoPath := app.MustComponent[wallet.Wallet](a).RepoPath()
|
||||
f.lang = validateLanguage(app.MustComponent[wallet.Wallet](a).FtsPrimaryLang())
|
||||
f.rootPath = filepath.Join(repoPath, ftsDir2)
|
||||
f.blevePath = filepath.Join(repoPath, ftsDir)
|
||||
f.ftsPath = filepath.Join(repoPath, ftsDir2, ftsVer)
|
||||
|
@ -245,14 +240,13 @@ func (f *ftSearchTantivy) Run(context.Context) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.schema = schema
|
||||
f.index = index
|
||||
f.parserPool = &fastjson.ParserPool{}
|
||||
|
||||
f.cleanupBleve()
|
||||
f.cleanUpOldIndexes()
|
||||
|
||||
err = index.RegisterTextAnalyzerSimple(tantivy.TokenizerSimple, 40, tantivy.English)
|
||||
err = index.RegisterTextAnalyzerSimple(tantivy.TokenizerSimple, 40, f.lang)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -307,31 +301,19 @@ func (f *ftSearchTantivy) Index(doc SearchDoc) error {
|
|||
|
||||
func (f *ftSearchTantivy) convertDoc(doc SearchDoc) (*tantivy.Document, error) {
|
||||
document := tantivy.NewDocument()
|
||||
err := document.AddField(fieldId, doc.Id, f.index)
|
||||
err := document.AddFields(doc.Id, f.index, fieldId, fieldIdRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = document.AddField(fieldIdRaw, doc.Id, f.index)
|
||||
err = document.AddField(doc.SpaceId, f.index, fieldSpace)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = document.AddField(fieldSpace, doc.SpaceId, f.index)
|
||||
err = document.AddFields(doc.Title, f.index, fieldTitle, fieldTitleZh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = document.AddField(fieldTitle, doc.Title, f.index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = document.AddField(fieldTitleZh, doc.Title, f.index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = document.AddField(fieldText, doc.Text, f.index)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = document.AddField(fieldTextZh, doc.Text, f.index)
|
||||
err = document.AddFields(doc.Text, f.index, fieldText, fieldTextZh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -410,7 +392,7 @@ func (f *ftSearchTantivy) performSearch(spaceId, query string, buildQueryFunc fu
|
|||
|
||||
return tantivy.GetSearchResults(
|
||||
result,
|
||||
f.schema,
|
||||
f.index,
|
||||
func(json string) (*DocumentMatch, error) {
|
||||
return parseSearchResult(json, p)
|
||||
},
|
||||
|
@ -549,11 +531,9 @@ func (f *ftSearchTantivy) DocCount() (uint64, error) {
|
|||
}
|
||||
|
||||
func (f *ftSearchTantivy) Close(ctx context.Context) error {
|
||||
f.schema = nil
|
||||
if f.index != nil {
|
||||
f.index.Free()
|
||||
f.index = nil
|
||||
f.schema = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -568,3 +548,17 @@ func prepareQuery(query string) string {
|
|||
query = strings.TrimSpace(query)
|
||||
return query
|
||||
}
|
||||
|
||||
func validateLanguage(lang string) tantivy.Language {
|
||||
tantivyLang := tantivy.Language(lang)
|
||||
switch tantivyLang {
|
||||
case tantivy.Arabic, tantivy.Armenian, tantivy.Basque, tantivy.Catalan, tantivy.Danish, tantivy.Dutch, tantivy.English,
|
||||
tantivy.Estonian, tantivy.Finnish, tantivy.French, tantivy.German, tantivy.Greek, tantivy.Hindi, tantivy.Hungarian,
|
||||
tantivy.Indonesian, tantivy.Irish, tantivy.Italian, tantivy.Lithuanian, tantivy.Nepali, tantivy.Norwegian,
|
||||
tantivy.Portuguese, tantivy.Romanian, tantivy.Russian, tantivy.Serbian, tantivy.Spanish, tantivy.Swedish,
|
||||
tantivy.Tamil, tantivy.Turkish, tantivy.Yiddish:
|
||||
return tantivyLang
|
||||
default:
|
||||
return tantivy.English
|
||||
}
|
||||
}
|
|
@ -273,21 +273,6 @@ func assertChineseFound(t *testing.T, tmpDir string) {
|
|||
_ = ft.Close(nil)
|
||||
}
|
||||
|
||||
func assertThaiSubstrFound(t *testing.T, tmpDir string) {
|
||||
fixture := newFixture(tmpDir, t)
|
||||
ft := fixture.ft
|
||||
require.NoError(t, ft.Index(SearchDoc{
|
||||
Id: "test",
|
||||
Title: "ตัวอย่าง",
|
||||
Text: "พรระเจ้า \n kumamon",
|
||||
}))
|
||||
|
||||
validateSearch(t, ft, "", "ระเ", 1)
|
||||
validateSearch(t, ft, "", "ระเ ma", 1)
|
||||
|
||||
_ = ft.Close(nil)
|
||||
}
|
||||
|
||||
func assertProperIds(t *testing.T, tmpDir string) {
|
||||
fixture := newFixture(tmpDir, t)
|
||||
ft := fixture.ft
|
|
@ -66,6 +66,10 @@ func newWalletStub(t testing.TB) wallet.Wallet {
|
|||
}
|
||||
}
|
||||
|
||||
func (w *walletStub) FtsPrimaryLang() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (w *walletStub) RepoPath() string {
|
||||
return w.tempDir
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ func NewStoreFixture(t testing.TB) *StoreFixture {
|
|||
walletService := mock_wallet.NewMockWallet(t)
|
||||
walletService.EXPECT().Name().Return(wallet.CName).Maybe()
|
||||
walletService.EXPECT().RepoPath().Return(t.TempDir())
|
||||
walletService.EXPECT().FtsPrimaryLang().Return("")
|
||||
|
||||
fullText := ftsearch.TantivyNew()
|
||||
testApp := &app.App{}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
bd658eb370191a0154ac47e0f61fa6d91e8313de7e64cfede5078fea93e4eb34 deps/libs/android-386.tar.gz
|
||||
a5d3083ac3eacbc0970153d0a5891412a595dcefe0dbe5b1134108ae5eac7072 deps/libs/android-amd64.tar.gz
|
||||
9411be7eda46fbd1548ca2804d1056b735a989df740129f67b924c407a9ce3a1 deps/libs/android-arm.tar.gz
|
||||
09a8b921b8d1385c7114ec67f6e665a448f7329642b178b84ecfdd7faf1828e1 deps/libs/android-arm64.tar.gz
|
||||
2f27b349b54d5982347f20b56ae8e4bacce5436fb3a1dd213f3c1bfc3ed60b0b deps/libs/darwin-amd64.tar.gz
|
||||
a518db7c5f9ebeb267966e390f788b76ee2643353af381e61110111546d3291b deps/libs/darwin-arm64.tar.gz
|
||||
1da257cbf8cf27bfeda21b5dc4c432412b58e06b80fe3653384b1bc5c12de004 deps/libs/ios-amd64.tar.gz
|
||||
6d7238b2743a23a745a52a1efb56760e3168e0601b292c96446afb7b737e5096 deps/libs/ios-arm64.tar.gz
|
||||
d412c6864853d916dd507508ec4a2f63b8eddc48a3e619e74dc7a90aaeb3f1a9 deps/libs/ios-arm64-sim.tar.gz
|
||||
35db326fee587c60cfec806847bff9706c8a209d46ee7449bb8664ee3ba815d5 deps/libs/linux-amd64-musl.tar.gz
|
||||
6029bdc9ef576e4473bb15e967255f76f25e12e211ae131cb887211916ca0fed deps/libs/linux-arm64-musl.tar.gz
|
||||
7475c129c4e18a93dfb8e583da95abf073d70f8a589291cf5d5ca6f8c71021e5 deps/libs/windows-amd64.tar.gz
|
||||
565dd299ef61edff535b20ec166f34f2399529b8254eed5d137a771a7b2b7c04 deps/libs/android-386.tar.gz
|
||||
34d9c7d4a400653ddbcf28e64a5c8e055c08ab675df6b921cebedb4c5e667254 deps/libs/android-amd64.tar.gz
|
||||
d90b501033763687f1ae136d69e284033594870c7143e50624799ff474e12f41 deps/libs/android-arm.tar.gz
|
||||
3939f7ad6a1d08a0a559566d0ae5195739317a0023381bcb719603a7e2cac10d deps/libs/android-arm64.tar.gz
|
||||
b7f7c3e82b1054a4c0755e7cd32f98d1dbe2ec55dab49f07e6620c8e2cd3ff83 deps/libs/darwin-amd64.tar.gz
|
||||
40cdb051d2e063eb374e1a911ca7926beb4586c41a0347e430dc18fe5c216790 deps/libs/darwin-arm64.tar.gz
|
||||
2dc93d6cb9356df9b5c330a6c566e1da1a4dfb32a17f1262080f2c1a875a5775 deps/libs/ios-amd64.tar.gz
|
||||
2a949a364f29c5801c3c18607dbc14b5edefdcd002746ce94c89f297bb4f620c deps/libs/ios-arm64.tar.gz
|
||||
b09afc40d37a37377579ec4096511fd88cc22cdd387518225a77f205c226130a deps/libs/ios-arm64-sim.tar.gz
|
||||
122010a6f287a3d3b169a64c26918bd5745a1190c99638e7e91a664172781cf7 deps/libs/linux-amd64-musl.tar.gz
|
||||
2b86930fcd938fe41413f4f915c90a2093d703179c61153ec4a007cdd2ed4a9c deps/libs/linux-arm64-musl.tar.gz
|
||||
2cdefb8975651849f6c5f41c5a934035d959e797c6fdef9a5a946ec9052e3bee deps/libs/windows-amd64.tar.gz
|
||||
|
|
|
@ -32,19 +32,31 @@ func TestTruncateEllipsized(t *testing.T) {
|
|||
expected: " ",
|
||||
},
|
||||
{
|
||||
name: "Divine emojie not fit",
|
||||
name: "Divine emoji not fit",
|
||||
text: "🌍",
|
||||
length: 1,
|
||||
expected: " …",
|
||||
},
|
||||
{
|
||||
name: "Divine emojies fit",
|
||||
name: "Big emoji fit",
|
||||
text: "👨👩👧👦",
|
||||
length: 11,
|
||||
expected: "👨👩👧👦",
|
||||
},
|
||||
{
|
||||
name: "Big emoji not fit",
|
||||
text: "👨👩👧👦",
|
||||
length: 10,
|
||||
expected: "👨\u200d👩\u200d👧 …",
|
||||
},
|
||||
{
|
||||
name: "Divine emoji fit",
|
||||
text: "🌍",
|
||||
length: 4,
|
||||
expected: "🌍",
|
||||
},
|
||||
{
|
||||
name: "Text with divine emojies not fit",
|
||||
name: "Text with divine emoji not fit",
|
||||
text: "Hello 🌍",
|
||||
length: 7,
|
||||
expected: "Hello …",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue