Commit graph

75 commits

Author SHA1 Message Date
RumovZ
fe8995e1a6 Add option to tag notes with missing media (#2379)
* Keep track of notes with missing media files

* Add option to tag notes with missing media

* Update ftl/core/media-check.ftl (dae)
2023-02-20 18:48:09 +10:00
Damien Elmes
b396313fe5 Update Rust deps (#2332)
* Temporarily disable hakari

* Upgrade compatible deps except Chrono

* Update semver-incompatible crates

* Re-enable hakari

* Update licenses & cargo-deny

* Fix new clippy lints

* Update to latest Rust
2023-01-18 22:24:29 +10:00
Damien Elmes
7216032e82 Switch Rust import style (#2330)
* Prepare to switch Rust import style

* Run nightly format

Closes #2320

* Clean up a few imports

* Enable comment wrapping

* Wrap comments
2023-01-18 21:39:55 +10:00
Damien Elmes
3707e54ffa Rework syncing code, and replace local sync server (#2329)
This PR replaces the existing Python-driven sync server with a new one in Rust.
The new server supports both collection and media syncing, and is compatible
with both the new protocol mentioned below, and older clients. A setting has
been added to the preferences screen to point Anki to a local server, and a
similar setting is likely to come to AnkiMobile soon.

Documentation is available here: <https://docs.ankiweb.net/sync-server.html>

In addition to the new server and refactoring, this PR also makes changes to the
sync protocol. The existing sync protocol places payloads and metadata inside a
multipart POST body, which causes a few headaches:

- Legacy clients build the request in a non-deterministic order, meaning the
entire request needs to be scanned to extract the metadata.
- Reqwest's multipart API directly writes the multipart body, without exposing
the resulting stream to us, making it harder to track the progress of the
transfer. We've been relying on a patched version of reqwest for timeouts,
which is a pain to keep up to date.

To address these issues, the metadata is now sent in a HTTP header, with the
data payload sent directly in the body. Instead of the slower gzip, we now
use zstd. The old timeout handling code has been replaced with a new implementation
that wraps the request and response body streams to track progress, allowing us
to drop the git dependencies for reqwest, hyper-timeout and tokio-io-timeout.

The main other change to the protocol is that one-way syncs no longer need to
downgrade the collection to schema 11 prior to sending.
2023-01-18 12:43:46 +10:00
Damien Elmes
a0222f6d57 Migrate from slog to tracing
The Rust community appear to have converged on tracing - it's used by
the Rust compiler, and receives close to 10x the number of downloads
that slog does. Its API is more ergonomic, and it does a much nicer
job with async rust.

To make this change, we no longer pass around explicit loggers, and rely
on a globally-registered one. The log file location has been changed
from one in each profile folder to a single one in the base folder. This
will remain empty for most users, since only errors are logged by default,
but may be useful for debugging future changes.
2022-12-24 10:44:40 +10:00
RumovZ
5db6318465 Refactor error handling (#2136)
* Add crate snafu

* Replace all inline structs in AnkiError

* Derive Snafu on AnkiError

* Use snafu for card type errors

* Use snafu whatever error for InvalidInput

* Use snafu for NotFoundError and improve message

* Use snafu for FileIoError to attach context

Remove IoError.
Add some context-attaching helpers to replace code returning bare
io::Errors.

* Add more context-attaching io helpers

* Add message, context and backtrace to new snafus

* Utilize error context and backtrace on frontend

* Rename LocalizedError -> BackendError.
* Remove DocumentedError.
* Have all backend exceptions inherit BackendError.

* Rename localized(_description) -> message

* Remove accidentally committed experimental trait

* invalid_input_context -> ok_or_invalid

* ensure_valid_input! -> require!

* Always return `Err` from `invalid_input!`

Instead of a Result to unwrap, the macro accepts a source error now.

* new_tempfile_in_parent -> new_tempfile_in_parent_of

* ok_or_not_found -> or_not_found

* ok_or_invalid -> or_invalid

* Add crate convert_case

* Use unqualified lowercase type name

* Remove uses of snafu::ensure

* Allow public construction of InvalidInputErrors (dae)

Needed to port the AnkiDroid changes.

* Make into_protobuf() public (dae)

Also required for AnkiDroid. Not sure why it worked previously - possible
bug in older Rust version?
2022-10-21 18:02:12 +10:00
Damien Elmes
553cadce56 Update to latest rules_rust and Rust 1.64 2022-09-24 11:12:58 +10:00
RumovZ
5c64aadb7a Garbage collect unused Fluent strings (#1482)
* Canonify import of i18n module

Should always be imported as `tr`, or `tr2` if there is a name collision
(Svelte).

* Add helper for garbage collecting ftl strings

Also add a serializer for ftl asts.

* Add helper for filter-mapping `DirEntry`s

* Fix `i18n_helpers/BUILD.bazel`

* run cargo-raze

* Refactor `garbage_collection.rs`

- Improve helper for file iterating
- Remove unused terms as well
- Fix issue with checking for nested messages by switching to a regex-
based approach (which runs before deleting)
- Some more refactorings and lint fixes

* Fix lints in `serialize.rs`

* Write json pretty and sorted

* Update `serialize.rs` and fix header

* Fix doc and remove `dbg!`

* Add binaries for ftl garbage collection

Also relax type constraints and strip debug tests.

* add rust_binary targets for i18n helpers (dae)

* add scripts to update desktop usage/garbage collect (dae)

Since we've already diverged from 2.1.49, we won't gain anything
from generating a stable json just yet. But once 2.1.50 is released,
we should run 'ftl/update-desktop-usage.sh stable'.

* add keys from AnkiMobile (dae)

* Mention caveats in `remove-unused.sh`
2021-11-12 18:19:01 +10:00
Damien Elmes
594f957bbb add a builder for Collection 2021-11-06 14:43:41 +10:00
abdo
4d3f2c0232 Strip isolation chars from filenames in Check Media screen 2021-09-27 22:15:37 +03:00
Damien Elmes
827f3e073a handle ampersand entities in image filenames
In the old HTML editor, filenames were % escaped before feeding them to
beautifulsoup, causing bare ampersands to be left alone. The new HTML
editor reads content from the DOM, where a bare ampersand has been
transformed into an &amp;, and that gets saved back into the field,
so the media check now needs to deal with it for images as well.

https://forums.ankiweb.net/t/causing-problems-with-image-names/12171
2021-08-19 23:43:40 +10:00
Damien Elmes
1e2ebd1c29 move from Python's URI escaping to IRI escaping in Rust
Should make non-Latin text readable in the HTML editor, without the
breakages reverted in the previous change.
2021-07-16 10:38:00 +10:00
Damien Elmes
ff095ed57b fix clippy lints for latest Rust 2021-06-21 13:09:36 +10:00
Damien Elmes
994d26937f remove some unneeded transactions from tests 2021-04-30 19:18:02 +10:00
Damien Elmes
03ca227fd4 make it more ergonomic to search directly via nodes in Rust 2021-04-30 11:37:55 +10:00
Damien Elmes
363a843d07 tidy up Rust imports
rustfmt can do this automatically, but only when run with a nightly
toolchain, so it needs to be manually done for now - see rslib/rusfmt.toml
2021-04-18 18:38:54 +10:00
Damien Elmes
cfe02d5df4 switch DbError to tuple type 2021-04-01 17:34:03 +10:00
Damien Elmes
cc54a9251e crate::err -> crate::error 2021-04-01 16:07:13 +10:00
Damien Elmes
d793c30526 switch NoteType to Notetype
When used as a variable, we were typically calling it a 'notetype', not
a 'note type'.
2021-03-27 22:03:19 +10:00
Damien Elmes
a90d5aa359 use mixed case for abbreviations in Rust code
So, this is fun. Apparently "DeckId" is considered preferable to the
"DeckID" were were using until now, and the latest clippy will start
warning about it. We could of course disable the warning, but probably
better to bite the bullet and switch to the naming that's generally
considered best.
2021-03-27 19:53:33 +10:00
Damien Elmes
9a7f0f9f5d i18n->tr in rslib/ to match Python/TS code 2021-03-27 12:09:51 +10:00
Damien Elmes
27c35cf2c5 update multi-arg TR references, where some needed reordering 2021-03-27 10:49:40 +10:00
Damien Elmes
d7005803bc update 1 arg tr strings in rslib 2021-03-27 10:39:53 +10:00
Damien Elmes
51f5df600f update no-arg TR references in rslib/ 2021-03-26 23:16:08 +10:00
Damien Elmes
0c63a7c8c4 rework translation handling
Instead of generating a fluent.proto file with a giant enum, create
a .json file representing the translations that downstream consumers
can use for code generation.

This enables the generation of a separate method for each translation,
with a docstring that shows the actual text, and any required arguments
listed in the function signature.

The codebase is still using the old enum for now; updating it will need
to come in future commits, and the old enum will need to be kept
around, as add-ons are referencing it.

Other changes:

- move translation code into a separate crate
- store the translations on a per-file/module basis, which will allow
us to avoid sending 1000+ strings on each JS page load in the future
- drop the undocumented support for external .ftl files, that we weren't
using
- duplicate strings in translation files are now checked for at build
time
- fix i18n test failing when run outside Bazel
- drop slog dependency in i18n module
2021-03-26 09:41:32 +10:00
Damien Elmes
42e20461c0 undoable ops now return changes directly; add new *_ops.py files
- Introduced a new transact() method that wraps the return value
in a separate struct that describes the changes that were made.
- Changes are now gathered from the undo log, so we don't need to
guess at what was changed - eg if update_note() is called with identical
note contents, no changes are returned. Card changes will only be set
if cards were actually generated by the update_note() call, and tag
will only be set if a new tag was added.
- mw.perform_op() has been updated to expect the op to return the changes,
or a structure with the changes in it, and it will use them to fire the
change hook, instead of fetching the changes from undo_status(), so there
is no risk of race conditions.
- the various calls to mw.perform_op() have been split into separate
files like card_ops.py. Aside from making the code cleaner, this works
around a rather annoying issue with mypy. Because we run it with
no_strict_optional, mypy is happy to accept an operation that returns None,
despite the type signature saying it requires changes to be returned.
Turning no_strict_optional on for the whole codebase is not practical
at the moment, but we can enable it for individual files.

Still todo:
- The cursor keeps moving back to the start of a field when typing -
we need to ignore the refresh hook when we are the initiator.
- The busy cursor icon should probably be delayed a few hundreds ms.
- Still need to think about a nicer way of handling saveNow()
- op_made_changes(), op_affects_study_queue() might be better embedded
as properties in the object instead
2021-03-19 19:45:21 +10:00
Damien Elmes
cce0ee2b03 handle quoted html chars in media check
https://forums.ankiweb.net/t/unable-to-play-longer-audio-on-cards/1313/30
2020-09-04 09:36:38 +10:00
Damien Elmes
7f42500e53 rename some card+note fields in backend 2020-09-01 10:24:38 +10:00
Damien Elmes
41a47fcf01 fix some clippy lints 2020-08-26 19:02:56 +10:00
Damien Elmes
aaed0464e5 rework progress handling
- client now polls status instead of backend pushing it
- supports multiple threads
- update throttling happens in one place
2020-06-01 13:57:10 +10:00
Damien Elmes
0a87b1ef2c support disabling unicode normalization in notes 2020-05-12 21:13:34 +10:00
Damien Elmes
85528cabc5 use backend for genCards() and updateFieldCache() 2020-05-12 21:13:34 +10:00
Damien Elmes
3b07885911 handle changed sort field index 2020-05-12 21:13:33 +10:00
Damien Elmes
0c8763edf3 cache notetypes 2020-05-12 21:13:33 +10:00
Damien Elmes
6b8a45bcb6 more work towards note adding
Still a prototype at this stage - we'll likely want a caching layer
for note types, and I'm not sure of the merit of having fields in
a separate table, since they're almost always required.
2020-05-12 21:13:33 +10:00
Damien Elmes
638e69af91 move note db code to storage 2020-05-12 21:13:33 +10:00
Damien Elmes
9c41210cf4 use native struct for NoteType 2020-05-12 21:13:33 +10:00
Damien Elmes
96300f5858 migrate the schema11 usages to new structs/sql queries 2020-05-12 21:13:33 +10:00
Damien Elmes
475478cec5 split note types into separate tables
- store the config in protobuf instead of json
- still loading+saving in bulk for now
- code using the schema11 structs needs to be migrated
2020-05-12 21:13:33 +10:00
Damien Elmes
07b9671012 don't throw an error when a file is greater than MAXPATH
https://anki.tenderapp.com/discussions/ankidesktop/40931-check-media-error
2020-04-30 08:01:45 +10:00
Damien Elmes
93152043e1 report the missing filename in media check
https://anki.tenderapp.com/discussions/ankidesktop/40578-check-media-error
2020-04-17 17:17:42 +10:00
Damien Elmes
bca49bd054 load/save note types in backend
This allows us to normalize bad data, and is the first step towards
splitting note types into separate tables.
2020-04-08 10:05:07 +10:00
Damien Elmes
8f427dbbd7 FString -> TR 2020-04-01 18:16:43 +10:00
Damien Elmes
7b201fe7e6 ignore .DS_Store in trash
https://anki.tenderapp.com/discussions/ankidesktop/40035-anki-2123-on-macos-ds_store-files-in-new-anki-trash
2020-04-01 13:37:57 +10:00
Damien Elmes
0451a4d4e0 drop separate RequestContext/StorageContext 2020-03-29 12:12:35 +10:00
Damien Elmes
4150480709 NoteTypeID 2020-03-26 15:00:24 +10:00
Damien Elmes
4563fe36bc rename long filenames in fields if files renamed in a previous sync 2020-03-23 18:38:45 +10:00
Damien Elmes
b087ebc845 start on search tests 2020-03-20 21:15:23 +10:00
Damien Elmes
6c469a96eb finish the remaining searches
Searches that require multiple deck or note type lookups won't perform
very well at the moment - it either needs caching or to be split up
at the DB level.

Nothing tested yet.
2020-03-20 21:15:23 +10:00
Damien Elmes
c710580604 move media folder/db paths into collection
this breaks background media syncing for now
2020-03-20 21:15:23 +10:00