From 18851ace47673460faf8c5b24529fd5257a39d16 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 10 Jul 2021 19:52:31 +1000 Subject: [PATCH] split out cards and collection --- proto/anki/backend.proto | 272 +++++++----------------------- proto/anki/cards.proto | 64 +++++++ proto/anki/collection.proto | 111 ++++++++++++ pylib/anki/_backend/genbackend.py | 12 +- pylib/anki/cards.py | 13 +- pylib/anki/cards_pb2.pyi | 1 + pylib/anki/collection.py | 16 +- pylib/anki/collection_pb2.pyi | 1 + rslib/src/backend_proto.rs | 8 + ts/graphs/added.ts | 4 +- ts/graphs/card-counts.ts | 6 +- ts/graphs/ease.ts | 4 +- ts/graphs/future-due.ts | 10 +- ts/graphs/graph-helpers.ts | 4 +- ts/graphs/intervals.ts | 4 +- ts/lib/proto.ts | 3 +- 16 files changed, 287 insertions(+), 246 deletions(-) create mode 100644 proto/anki/cards.proto create mode 100644 proto/anki/collection.proto create mode 120000 pylib/anki/cards_pb2.pyi create mode 120000 pylib/anki/collection_pb2.pyi diff --git a/proto/anki/backend.proto b/proto/anki/backend.proto index 847f314b5..36a0cf79a 100644 --- a/proto/anki/backend.proto +++ b/proto/anki/backend.proto @@ -6,6 +6,8 @@ syntax = "proto3"; package anki.backend; import "anki/generic.proto"; +import "anki/cards.proto"; +import "anki/collection.proto"; // IDs used in RPC calls /////////////////////////////////////////////////////////// @@ -22,14 +24,6 @@ message NoteIds { repeated int64 note_ids = 1; } -message CardId { - int64 cid = 1; -} - -message CardIds { - repeated int64 cids = 1; -} - message DeckId { int64 did = 1; } @@ -74,45 +68,49 @@ service SchedulingService { rpc ExtendLimits(ExtendLimitsRequest) returns (generic.Empty); rpc CountsForDeckToday(DeckId) returns (CountsForDeckTodayResponse); rpc CongratsInfo(generic.Empty) returns (CongratsInfoResponse); - rpc RestoreBuriedAndSuspendedCards(CardIds) returns (OpChanges); - rpc UnburyDeck(UnburyDeckRequest) returns (OpChanges); + rpc RestoreBuriedAndSuspendedCards(cards.CardIds) + returns (collection.OpChanges); + rpc UnburyDeck(UnburyDeckRequest) returns (collection.OpChanges); rpc BuryOrSuspendCards(BuryOrSuspendCardsRequest) - returns (OpChangesWithCount); - rpc EmptyFilteredDeck(DeckId) returns (OpChanges); - rpc RebuildFilteredDeck(DeckId) returns (OpChangesWithCount); - rpc ScheduleCardsAsNew(ScheduleCardsAsNewRequest) returns (OpChanges); - rpc SetDueDate(SetDueDateRequest) returns (OpChanges); - rpc SortCards(SortCardsRequest) returns (OpChangesWithCount); - rpc SortDeck(SortDeckRequest) returns (OpChangesWithCount); - rpc GetNextCardStates(CardId) returns (NextCardStates); + returns (collection.OpChangesWithCount); + rpc EmptyFilteredDeck(DeckId) returns (collection.OpChanges); + rpc RebuildFilteredDeck(DeckId) returns (collection.OpChangesWithCount); + rpc ScheduleCardsAsNew(ScheduleCardsAsNewRequest) + returns (collection.OpChanges); + rpc SetDueDate(SetDueDateRequest) returns (collection.OpChanges); + rpc SortCards(SortCardsRequest) returns (collection.OpChangesWithCount); + rpc SortDeck(SortDeckRequest) returns (collection.OpChangesWithCount); + rpc GetNextCardStates(cards.CardId) returns (NextCardStates); rpc DescribeNextStates(NextCardStates) returns (generic.StringList); rpc StateIsLeech(SchedulingState) returns (generic.Bool); - rpc AnswerCard(CardAnswer) returns (OpChanges); + rpc AnswerCard(CardAnswer) returns (collection.OpChanges); rpc UpgradeScheduler(generic.Empty) returns (generic.Empty); rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards); } service DecksService { - rpc AddDeckLegacy(generic.Json) returns (OpChangesWithId); + rpc AddDeckLegacy(generic.Json) returns (collection.OpChangesWithId); rpc AddOrUpdateDeckLegacy(AddOrUpdateDeckLegacyRequest) returns (DeckId); rpc DeckTree(DeckTreeRequest) returns (DeckTreeNode); rpc DeckTreeLegacy(generic.Empty) returns (generic.Json); rpc GetAllDecksLegacy(generic.Empty) returns (generic.Json); rpc GetDeckIdByName(generic.String) returns (DeckId); rpc GetDeck(DeckId) returns (Deck); - rpc UpdateDeck(Deck) returns (OpChanges); - rpc UpdateDeckLegacy(generic.Json) returns (OpChanges); - rpc SetDeckCollapsed(SetDeckCollapsedRequest) returns (OpChanges); + rpc UpdateDeck(Deck) returns (collection.OpChanges); + rpc UpdateDeckLegacy(generic.Json) returns (collection.OpChanges); + rpc SetDeckCollapsed(SetDeckCollapsedRequest) returns (collection.OpChanges); rpc GetDeckLegacy(DeckId) returns (generic.Json); rpc GetDeckNames(GetDeckNamesRequest) returns (DeckNames); rpc NewDeckLegacy(generic.Bool) returns (generic.Json); - rpc RemoveDecks(DeckIds) returns (OpChangesWithCount); - rpc ReparentDecks(ReparentDecksRequest) returns (OpChangesWithCount); - rpc RenameDeck(RenameDeckRequest) returns (OpChanges); + rpc RemoveDecks(DeckIds) returns (collection.OpChangesWithCount); + rpc ReparentDecks(ReparentDecksRequest) + returns (collection.OpChangesWithCount); + rpc RenameDeck(RenameDeckRequest) returns (collection.OpChanges); rpc GetOrCreateFilteredDeck(DeckId) returns (FilteredDeckForUpdate); - rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate) returns (OpChangesWithId); + rpc AddOrUpdateFilteredDeck(FilteredDeckForUpdate) + returns (collection.OpChangesWithId); rpc FilteredDeckOrderLabels(generic.Empty) returns (generic.StringList); - rpc SetCurrentDeck(DeckId) returns (OpChanges); + rpc SetCurrentDeck(DeckId) returns (collection.OpChanges); rpc GetCurrentDeck(generic.Empty) returns (Deck); } @@ -121,15 +119,16 @@ service NotesService { rpc AddNote(AddNoteRequest) returns (AddNoteResponse); rpc DefaultsForAdding(DefaultsForAddingRequest) returns (DeckAndNotetype); rpc DefaultDeckForNotetype(NotetypeId) returns (DeckId); - rpc UpdateNote(UpdateNoteRequest) returns (OpChanges); + rpc UpdateNote(UpdateNoteRequest) returns (collection.OpChanges); rpc GetNote(NoteId) returns (Note); - rpc RemoveNotes(RemoveNotesRequest) returns (OpChangesWithCount); + rpc RemoveNotes(RemoveNotesRequest) returns (collection.OpChangesWithCount); rpc ClozeNumbersInNote(Note) returns (ClozeNumbersInNoteResponse); - rpc AfterNoteUpdates(AfterNoteUpdatesRequest) returns (OpChangesWithCount); + rpc AfterNoteUpdates(AfterNoteUpdatesRequest) + returns (collection.OpChangesWithCount); rpc FieldNamesForNotes(FieldNamesForNotesRequest) returns (FieldNamesForNotesResponse); rpc NoteFieldsCheck(Note) returns (NoteFieldsCheckResponse); - rpc CardsOfNote(NoteId) returns (CardIds); + rpc CardsOfNote(NoteId) returns (cards.CardIds); } service SyncService { @@ -147,23 +146,23 @@ service SyncService { service ConfigService { rpc GetConfigJson(generic.String) returns (generic.Json); - rpc SetConfigJson(SetConfigJsonRequest) returns (OpChanges); + rpc SetConfigJson(SetConfigJsonRequest) returns (collection.OpChanges); rpc SetConfigJsonNoUndo(SetConfigJsonRequest) returns (generic.Empty); - rpc RemoveConfig(generic.String) returns (OpChanges); + rpc RemoveConfig(generic.String) returns (collection.OpChanges); rpc GetAllConfig(generic.Empty) returns (generic.Json); rpc GetConfigBool(Config.Bool) returns (generic.Bool); - rpc SetConfigBool(SetConfigBoolRequest) returns (OpChanges); + rpc SetConfigBool(SetConfigBoolRequest) returns (collection.OpChanges); rpc GetConfigString(Config.String) returns (generic.String); - rpc SetConfigString(SetConfigStringRequest) returns (OpChanges); + rpc SetConfigString(SetConfigStringRequest) returns (collection.OpChanges); rpc GetPreferences(generic.Empty) returns (Preferences); - rpc SetPreferences(Preferences) returns (OpChanges); + rpc SetPreferences(Preferences) returns (collection.OpChanges); } service NotetypesService { - rpc AddNotetype(Notetype) returns (OpChangesWithId); - rpc UpdateNotetype(Notetype) returns (OpChanges); - rpc AddNotetypeLegacy(generic.Json) returns (OpChangesWithId); - rpc UpdateNotetypeLegacy(generic.Json) returns (OpChanges); + rpc AddNotetype(Notetype) returns (collection.OpChangesWithId); + rpc UpdateNotetype(Notetype) returns (collection.OpChanges); + rpc AddNotetypeLegacy(generic.Json) returns (collection.OpChangesWithId); + rpc UpdateNotetypeLegacy(generic.Json) returns (collection.OpChanges); rpc AddOrUpdateNotetype(AddOrUpdateNotetypeRequest) returns (NotetypeId); rpc GetStockNotetypeLegacy(StockNotetype) returns (generic.Json); rpc GetNotetype(NotetypeId) returns (Notetype); @@ -171,14 +170,14 @@ service NotetypesService { rpc GetNotetypeNames(generic.Empty) returns (NotetypeNames); rpc GetNotetypeNamesAndCounts(generic.Empty) returns (NotetypeUseCounts); rpc GetNotetypeIdByName(generic.String) returns (NotetypeId); - rpc RemoveNotetype(NotetypeId) returns (OpChanges); + rpc RemoveNotetype(NotetypeId) returns (collection.OpChanges); rpc GetAuxNotetypeConfigKey(GetAuxConfigKeyRequest) returns (generic.String); rpc GetAuxTemplateConfigKey(GetAuxTemplateConfigKeyRequest) returns (generic.String); rpc GetSingleNotetypeOfNotes(NoteIds) returns (NotetypeId); rpc GetChangeNotetypeInfo(GetChangeNotetypeInfoRequest) returns (ChangeNotetypeInfo); - rpc ChangeNotetype(ChangeNotetypeRequest) returns (OpChanges); + rpc ChangeNotetype(ChangeNotetypeRequest) returns (collection.OpChanges); } service CardRenderingService { @@ -203,20 +202,24 @@ service DeckConfigService { rpc NewDeckConfigLegacy(generic.Empty) returns (generic.Json); rpc RemoveDeckConfig(DeckConfigId) returns (generic.Empty); rpc GetDeckConfigsForUpdate(DeckId) returns (DeckConfigsForUpdate); - rpc UpdateDeckConfigs(UpdateDeckConfigsRequest) returns (OpChanges); + rpc UpdateDeckConfigs(UpdateDeckConfigsRequest) + returns (collection.OpChanges); } service TagsService { - rpc ClearUnusedTags(generic.Empty) returns (OpChangesWithCount); + rpc ClearUnusedTags(generic.Empty) returns (collection.OpChangesWithCount); rpc AllTags(generic.Empty) returns (generic.StringList); - rpc RemoveTags(generic.String) returns (OpChangesWithCount); - rpc SetTagCollapsed(SetTagCollapsedRequest) returns (OpChanges); + rpc RemoveTags(generic.String) returns (collection.OpChangesWithCount); + rpc SetTagCollapsed(SetTagCollapsedRequest) returns (collection.OpChanges); rpc TagTree(generic.Empty) returns (TagTreeNode); - rpc ReparentTags(ReparentTagsRequest) returns (OpChangesWithCount); - rpc RenameTags(RenameTagsRequest) returns (OpChangesWithCount); - rpc AddNoteTags(NoteIdsAndTagsRequest) returns (OpChangesWithCount); - rpc RemoveNoteTags(NoteIdsAndTagsRequest) returns (OpChangesWithCount); - rpc FindAndReplaceTag(FindAndReplaceTagRequest) returns (OpChangesWithCount); + rpc ReparentTags(ReparentTagsRequest) returns (collection.OpChangesWithCount); + rpc RenameTags(RenameTagsRequest) returns (collection.OpChangesWithCount); + rpc AddNoteTags(NoteIdsAndTagsRequest) + returns (collection.OpChangesWithCount); + rpc RemoveNoteTags(NoteIdsAndTagsRequest) + returns (collection.OpChangesWithCount); + rpc FindAndReplaceTag(FindAndReplaceTagRequest) + returns (collection.OpChangesWithCount); } service SearchService { @@ -225,14 +228,15 @@ service SearchService { rpc SearchNotes(SearchRequest) returns (SearchResponse); rpc JoinSearchNodes(JoinSearchNodesRequest) returns (generic.String); rpc ReplaceSearchNode(ReplaceSearchNodeRequest) returns (generic.String); - rpc FindAndReplace(FindAndReplaceRequest) returns (OpChangesWithCount); + rpc FindAndReplace(FindAndReplaceRequest) + returns (collection.OpChangesWithCount); rpc AllBrowserColumns(generic.Empty) returns (BrowserColumns); rpc BrowserRowForId(generic.Int64) returns (BrowserRow); rpc SetActiveBrowserColumns(generic.StringList) returns (generic.Empty); } service StatsService { - rpc CardStats(CardId) returns (generic.String); + rpc CardStats(cards.CardId) returns (generic.String); rpc Graphs(GraphsRequest) returns (GraphsResponse); rpc GetGraphPreferences(generic.Empty) returns (GraphPreferences); rpc SetGraphPreferences(GraphPreferences) returns (generic.Empty); @@ -246,27 +250,6 @@ service MediaService { rpc RestoreTrash(generic.Empty) returns (generic.Empty); } -service CollectionService { - rpc OpenCollection(OpenCollectionRequest) returns (generic.Empty); - rpc CloseCollection(CloseCollectionRequest) returns (generic.Empty); - rpc CheckDatabase(generic.Empty) returns (CheckDatabaseResponse); - rpc GetUndoStatus(generic.Empty) returns (UndoStatus); - rpc Undo(generic.Empty) returns (OpChangesAfterUndo); - rpc Redo(generic.Empty) returns (OpChangesAfterUndo); - rpc AddCustomUndoEntry(generic.String) returns (generic.UInt32); - rpc MergeUndoEntries(generic.UInt32) returns (OpChanges); - rpc LatestProgress(generic.Empty) returns (Progress); - rpc SetWantsAbort(generic.Empty) returns (generic.Empty); -} - -service CardsService { - rpc GetCard(CardId) returns (Card); - rpc UpdateCard(UpdateCardRequest) returns (OpChanges); - rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty); - rpc SetDeck(SetDeckRequest) returns (OpChangesWithCount); - rpc SetFlag(SetFlagRequest) returns (OpChangesWithCount); -} - // Protobuf stored in .anki2 files // These should be moved to a separate file in the future /////////////////////////////////////////////////////////// @@ -518,27 +501,6 @@ message Note { repeated string fields = 7; } -message Card { - int64 id = 1; - int64 note_id = 2; - int64 deck_id = 3; - uint32 template_idx = 4; - int64 mtime_secs = 5; - sint32 usn = 6; - uint32 ctype = 7; - sint32 queue = 8; - sint32 due = 9; - uint32 interval = 10; - uint32 ease_factor = 11; - uint32 reps = 12; - uint32 lapses = 13; - uint32 remaining_steps = 14; - sint32 original_due = 15; - int64 original_deck_id = 16; - uint32 flags = 17; - string data = 18; -} - // Backend /////////////////////////////////////////////////////////// @@ -581,42 +543,6 @@ message BackendError { Kind kind = 2; } -// Progress -/////////////////////////////////////////////////////////// - -message Progress { - message MediaSync { - string checked = 1; - string added = 2; - string removed = 3; - } - - message FullSync { - uint32 transferred = 1; - uint32 total = 2; - } - - message NormalSync { - string stage = 1; - string added = 2; - string removed = 3; - } - - message DatabaseCheck { - string stage = 1; - uint32 stage_total = 2; - uint32 stage_current = 3; - } - oneof value { - generic.Empty none = 1; - MediaSync media_sync = 2; - string media_check = 3; - FullSync full_sync = 4; - NormalSync normal_sync = 5; - DatabaseCheck database_check = 6; - } -} - // Messages /////////////////////////////////////////////////////////// @@ -754,13 +680,6 @@ message CongratsLearnMessageRequest { uint32 remaining = 2; } -message OpenCollectionRequest { - string collection_path = 1; - string media_folder_path = 2; - string media_db_path = 3; - string log_path = 4; -} - message SearchRequest { string search = 1; SortOrder order = 2; @@ -863,10 +782,6 @@ message ReplaceSearchNodeRequest { SearchNode replacement_node = 2; } -message CloseCollectionRequest { - bool downgrade_to_schema11 = 1; -} - message DeckConfigsForUpdate { message ConfigWithExtra { DeckConfig config = 1; @@ -984,7 +899,7 @@ message AddNoteRequest { message AddNoteResponse { int64 note_id = 1; - OpChanges changes = 2; + collection.OpChanges changes = 2; } message UpdateNoteRequest { @@ -992,11 +907,6 @@ message UpdateNoteRequest { bool skip_undo_entry = 2; } -message UpdateCardRequest { - Card card = 1; - bool skip_undo_entry = 2; -} - message EmptyCardsReport { message NoteWithEmptyCards { int64 note_id = 1; @@ -1101,10 +1011,6 @@ message FindAndReplaceTagRequest { bool match_case = 5; } -message CheckDatabaseResponse { - repeated string problems = 1; -} - message Preferences { message Scheduling { enum NewReviewMix { @@ -1230,10 +1136,6 @@ message RemoveNotesRequest { repeated int64 card_ids = 2; } -message RemoveCardsRequest { - repeated int64 card_ids = 1; -} - message UpdateStatsRequest { int64 deck_id = 1; int32 new_delta = 2; @@ -1258,7 +1160,7 @@ message GraphsRequest { } message GraphsResponse { - repeated Card cards = 1; + repeated cards.Card cards = 1; repeated RevlogEntry revlog = 2; uint32 days_elapsed = 3; // Based on rollover hour @@ -1357,11 +1259,6 @@ message SortDeckRequest { bool randomize = 2; } -message SetDeckRequest { - repeated int64 card_ids = 1; - int64 deck_id = 2; -} - message Config { message Bool { enum Key { @@ -1496,7 +1393,7 @@ message QueuedCards { REVIEW = 2; } message QueuedCard { - Card card = 1; + cards.Card card = 1; Queue queue = 2; NextCardStates next_states = 3; } @@ -1507,48 +1404,6 @@ message QueuedCards { uint32 review_count = 4; } -message OpChanges { - bool card = 1; - bool note = 2; - bool deck = 3; - bool tag = 4; - bool notetype = 5; - bool config = 6; - bool deck_config = 11; - bool mtime = 12; - - bool browser_table = 7; - bool browser_sidebar = 8; - // editor and displayed card in review screen - bool note_text = 9; - // whether to call .reset() and getCard() - bool study_queues = 10; -} - -message OpChangesWithCount { - uint32 count = 1; - OpChanges changes = 2; -} - -message OpChangesWithId { - int64 id = 1; - OpChanges changes = 2; -} - -message UndoStatus { - string undo = 1; - string redo = 2; - uint32 last_step = 3; -} - -message OpChangesAfterUndo { - OpChanges changes = 1; - string operation = 2; - int64 reverted_to_timestamp = 3; - UndoStatus new_status = 4; - uint32 counter = 5; -} - message DefaultsForAddingRequest { int64 home_deck_of_current_review_card = 1; } @@ -1569,11 +1424,6 @@ message FilteredDeckForUpdate { Deck.Filtered config = 3; } -message SetFlagRequest { - repeated int64 card_ids = 1; - uint32 flag = 2; -} - message GetAuxConfigKeyRequest { int64 id = 1; string key = 2; diff --git a/proto/anki/cards.proto b/proto/anki/cards.proto new file mode 100644 index 000000000..26b260982 --- /dev/null +++ b/proto/anki/cards.proto @@ -0,0 +1,64 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.cards; + +import "anki/generic.proto"; +import "anki/collection.proto"; + +service CardsService { + rpc GetCard(CardId) returns (Card); + rpc UpdateCard(UpdateCardRequest) returns (collection.OpChanges); + rpc RemoveCards(RemoveCardsRequest) returns (generic.Empty); + rpc SetDeck(SetDeckRequest) returns (collection.OpChangesWithCount); + rpc SetFlag(SetFlagRequest) returns (collection.OpChangesWithCount); +} +message CardId { + int64 cid = 1; +} + +message CardIds { + repeated int64 cids = 1; +} + +message Card { + int64 id = 1; + int64 note_id = 2; + int64 deck_id = 3; + uint32 template_idx = 4; + int64 mtime_secs = 5; + sint32 usn = 6; + uint32 ctype = 7; + sint32 queue = 8; + sint32 due = 9; + uint32 interval = 10; + uint32 ease_factor = 11; + uint32 reps = 12; + uint32 lapses = 13; + uint32 remaining_steps = 14; + sint32 original_due = 15; + int64 original_deck_id = 16; + uint32 flags = 17; + string data = 18; +} + +message UpdateCardRequest { + Card card = 1; + bool skip_undo_entry = 2; +} + +message RemoveCardsRequest { + repeated int64 card_ids = 1; +} + +message SetDeckRequest { + repeated int64 card_ids = 1; + int64 deck_id = 2; +} + +message SetFlagRequest { + repeated int64 card_ids = 1; + uint32 flag = 2; +} diff --git a/proto/anki/collection.proto b/proto/anki/collection.proto new file mode 100644 index 000000000..21465371d --- /dev/null +++ b/proto/anki/collection.proto @@ -0,0 +1,111 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.collection; + +import "anki/generic.proto"; + +service CollectionService { + rpc OpenCollection(OpenCollectionRequest) returns (generic.Empty); + rpc CloseCollection(CloseCollectionRequest) returns (generic.Empty); + rpc CheckDatabase(generic.Empty) returns (CheckDatabaseResponse); + rpc GetUndoStatus(generic.Empty) returns (UndoStatus); + rpc Undo(generic.Empty) returns (OpChangesAfterUndo); + rpc Redo(generic.Empty) returns (OpChangesAfterUndo); + rpc AddCustomUndoEntry(generic.String) returns (generic.UInt32); + rpc MergeUndoEntries(generic.UInt32) returns (OpChanges); + rpc LatestProgress(generic.Empty) returns (Progress); + rpc SetWantsAbort(generic.Empty) returns (generic.Empty); +} + +message OpenCollectionRequest { + string collection_path = 1; + string media_folder_path = 2; + string media_db_path = 3; + string log_path = 4; +} + +message CloseCollectionRequest { + bool downgrade_to_schema11 = 1; +} + +message CheckDatabaseResponse { + repeated string problems = 1; +} + +message OpChanges { + bool card = 1; + bool note = 2; + bool deck = 3; + bool tag = 4; + bool notetype = 5; + bool config = 6; + bool deck_config = 11; + bool mtime = 12; + + bool browser_table = 7; + bool browser_sidebar = 8; + // editor and displayed card in review screen + bool note_text = 9; + // whether to call .reset() and getCard() + bool study_queues = 10; +} + +message OpChangesWithCount { + uint32 count = 1; + OpChanges changes = 2; +} + +message OpChangesWithId { + int64 id = 1; + OpChanges changes = 2; +} + +message UndoStatus { + string undo = 1; + string redo = 2; + uint32 last_step = 3; +} + +message OpChangesAfterUndo { + OpChanges changes = 1; + string operation = 2; + int64 reverted_to_timestamp = 3; + UndoStatus new_status = 4; + uint32 counter = 5; +} + +message Progress { + message MediaSync { + string checked = 1; + string added = 2; + string removed = 3; + } + + message FullSync { + uint32 transferred = 1; + uint32 total = 2; + } + + message NormalSync { + string stage = 1; + string added = 2; + string removed = 3; + } + + message DatabaseCheck { + string stage = 1; + uint32 stage_total = 2; + uint32 stage_current = 3; + } + oneof value { + generic.Empty none = 1; + MediaSync media_sync = 2; + string media_check = 3; + FullSync full_sync = 4; + NormalSync normal_sync = 5; + DatabaseCheck database_check = 6; + } +} diff --git a/pylib/anki/_backend/genbackend.py b/pylib/anki/_backend/genbackend.py index 3d4031c1b..4d8530cbb 100755 --- a/pylib/anki/_backend/genbackend.py +++ b/pylib/anki/_backend/genbackend.py @@ -10,6 +10,8 @@ import google.protobuf.descriptor import anki.backend_pb2 import anki.i18n_pb2 +import anki.cards_pb2 +import anki.collection_pb2 import stringcase @@ -165,14 +167,18 @@ def render_service( out.append(render_method(service_index, method_index, method)) -service_modules = dict(I18N="i18n") +service_modules = dict( + I18N=anki.i18n_pb2, + COLLECTION=anki.collection_pb2, + CARDS=anki.cards_pb2, +) for service in anki.backend_pb2.ServiceIndex.DESCRIPTOR.values: # SERVICE_INDEX_TEST -> _TESTSERVICE base = service.name.replace("SERVICE_INDEX_", "") - service_pkg = (service_modules.get(base) or "backend") + "" + service_pkg = service_modules.get(base) or anki.backend_pb2 service_var = "_" + base.replace("_", "") + "SERVICE" - service_obj = getattr(getattr(anki, service_pkg + "_pb2"), service_var) + service_obj = getattr(service_pkg, service_var) service_index = service.number render_service(service_obj, service_index) diff --git a/pylib/anki/cards.py b/pylib/anki/cards.py index 933f044ff..769332f8d 100644 --- a/pylib/anki/cards.py +++ b/pylib/anki/cards.py @@ -10,8 +10,7 @@ import time from typing import List, NewType, Optional import anki # pylint: disable=unused-import -import anki.backend_pb2 as _pb -from anki import hooks +from anki import cards_pb2, hooks from anki._legacy import DeprecatedNamesMixin, deprecated from anki.consts import * from anki.models import NotetypeDict, TemplateDict @@ -31,7 +30,7 @@ from anki.sound import AVTag # types CardId = NewType("CardId", int) -BackendCard = _pb.Card +BackendCard = cards_pb2.Card class Card(DeprecatedNamesMixin): @@ -62,14 +61,14 @@ class Card(DeprecatedNamesMixin): self._load_from_backend_card(backend_card) else: # new card with defaults - self._load_from_backend_card(_pb.Card()) + self._load_from_backend_card(cards_pb2.Card()) def load(self) -> None: card = self.col._backend.get_card(self.id) assert card self._load_from_backend_card(card) - def _load_from_backend_card(self, card: _pb.Card) -> None: + def _load_from_backend_card(self, card: cards_pb2.Card) -> None: self._render_output = None self._note = None self.id = CardId(card.id) @@ -91,9 +90,9 @@ class Card(DeprecatedNamesMixin): self.flags = card.flags self.data = card.data - def _to_backend_card(self) -> _pb.Card: + def _to_backend_card(self) -> cards_pb2.Card: # mtime & usn are set by backend - return _pb.Card( + return cards_pb2.Card( id=self.id, note_id=self.nid, deck_id=self.did, diff --git a/pylib/anki/cards_pb2.pyi b/pylib/anki/cards_pb2.pyi new file mode 120000 index 000000000..f503a0f31 --- /dev/null +++ b/pylib/anki/cards_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/cards_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index 83e406927..c331edd09 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -8,20 +8,20 @@ from __future__ import annotations from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Union, cast import anki.backend_pb2 as _pb - -# protobuf we publicly export - listed first to avoid circular imports +from anki import collection_pb2 from anki._legacy import DeprecatedNamesMixin, deprecated +# protobuf we publicly export - listed first to avoid circular imports SearchNode = _pb.SearchNode -Progress = _pb.Progress +Progress = collection_pb2.Progress EmptyCardsReport = _pb.EmptyCardsReport GraphPreferences = _pb.GraphPreferences Preferences = _pb.Preferences -UndoStatus = _pb.UndoStatus -OpChanges = _pb.OpChanges -OpChangesWithCount = _pb.OpChangesWithCount -OpChangesWithId = _pb.OpChangesWithId -OpChangesAfterUndo = _pb.OpChangesAfterUndo +UndoStatus = collection_pb2.UndoStatus +OpChanges = collection_pb2.OpChanges +OpChangesWithCount = collection_pb2.OpChangesWithCount +OpChangesWithId = collection_pb2.OpChangesWithId +OpChangesAfterUndo = collection_pb2.OpChangesAfterUndo DefaultsForAdding = _pb.DeckAndNotetype BrowserRow = _pb.BrowserRow BrowserColumns = _pb.BrowserColumns diff --git a/pylib/anki/collection_pb2.pyi b/pylib/anki/collection_pb2.pyi new file mode 120000 index 000000000..1c9fc3872 --- /dev/null +++ b/pylib/anki/collection_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/collection_pb2.pyi \ No newline at end of file diff --git a/rslib/src/backend_proto.rs b/rslib/src/backend_proto.rs index 8c50836f5..f0cbcd718 100644 --- a/rslib/src/backend_proto.rs +++ b/rslib/src/backend_proto.rs @@ -10,7 +10,15 @@ pub mod i18n { pub mod generic { include!(concat!(env!("OUT_DIR"), "/anki.generic.rs")); } +pub mod cards { + include!(concat!(env!("OUT_DIR"), "/anki.cards.rs")); +} +pub mod collection { + include!(concat!(env!("OUT_DIR"), "/anki.collection.rs")); +} pub use backend::*; +pub use cards::*; +pub use collection::*; pub use generic::*; pub use i18n::*; diff --git a/ts/graphs/added.ts b/ts/graphs/added.ts index 37f962bf3..75575cccc 100644 --- a/ts/graphs/added.ts +++ b/ts/graphs/added.ts @@ -6,7 +6,7 @@ @typescript-eslint/no-explicit-any: "off", */ -import type { Backend } from "lib/proto"; +import type { Backend, Cards } from "lib/proto"; import { extent, @@ -29,7 +29,7 @@ export interface GraphData { } export function gatherData(data: Backend.GraphsResponse): GraphData { - const daysAdded = (data.cards as Backend.Card[]).map((card) => { + const daysAdded = (data.cards as Cards.Card[]).map((card) => { const elapsedSecs = (card.id as number) / 1000 - data.nextDayAtSecs; return Math.ceil(elapsedSecs / 86400); }); diff --git a/ts/graphs/card-counts.ts b/ts/graphs/card-counts.ts index 2179a54c4..1493db1e4 100644 --- a/ts/graphs/card-counts.ts +++ b/ts/graphs/card-counts.ts @@ -7,7 +7,7 @@ */ import { CardQueue, CardType } from "lib/cards"; -import type { Backend } from "lib/proto"; +import type { Backend, Cards } from "lib/proto"; import { schemeGreens, schemeBlues, @@ -41,7 +41,7 @@ const barColours = [ "grey" /* buried */, ]; -function countCards(cards: Backend.ICard[], separateInactive: boolean): Count[] { +function countCards(cards: Cards.ICard[], separateInactive: boolean): Count[] { let newCards = 0; let learn = 0; let relearn = 0; @@ -50,7 +50,7 @@ function countCards(cards: Backend.ICard[], separateInactive: boolean): Count[] let suspended = 0; let buried = 0; - for (const card of cards as Backend.Card[]) { + for (const card of cards as Cards.Card[]) { if (separateInactive) { switch (card.queue) { case CardQueue.Suspended: diff --git a/ts/graphs/ease.ts b/ts/graphs/ease.ts index 979bd64a7..59d437913 100644 --- a/ts/graphs/ease.ts +++ b/ts/graphs/ease.ts @@ -6,7 +6,7 @@ @typescript-eslint/no-explicit-any: "off", */ -import type { Backend } from "lib/proto"; +import type { Backend, Cards } from "lib/proto"; import { extent, histogram, @@ -27,7 +27,7 @@ export interface GraphData { } export function gatherData(data: Backend.GraphsResponse): GraphData { - const eases = (data.cards as Backend.Card[]) + const eases = (data.cards as Cards.Card[]) .filter((c) => [CardType.Review, CardType.Relearn].includes(c.ctype)) .map((c) => c.easeFactor / 10); return { eases }; diff --git a/ts/graphs/future-due.ts b/ts/graphs/future-due.ts index 0cb9054b2..0748f01c6 100644 --- a/ts/graphs/future-due.ts +++ b/ts/graphs/future-due.ts @@ -6,7 +6,7 @@ @typescript-eslint/no-explicit-any: "off", */ -import type { Backend } from "lib/proto"; +import type { Backend, Cards } from "lib/proto"; import { extent, histogram, @@ -31,12 +31,12 @@ export interface GraphData { } export function gatherData(data: Backend.GraphsResponse): GraphData { - const isLearning = (card: Backend.Card): boolean => + const isLearning = (card: Cards.Card): boolean => [CardQueue.Learn, CardQueue.PreviewRepeat].includes(card.queue); let haveBacklog = false; - const due = (data.cards as Backend.Card[]) - .filter((c: Backend.Card) => { + const due = (data.cards as Cards.Card[]) + .filter((c: Cards.Card) => { // reviews return ( [CardQueue.Review, CardQueue.DayLearn].includes(c.queue) || @@ -44,7 +44,7 @@ export function gatherData(data: Backend.GraphsResponse): GraphData { isLearning(c) ); }) - .map((c: Backend.Card) => { + .map((c: Cards.Card) => { let dueDay: number; if (isLearning(c)) { diff --git a/ts/graphs/graph-helpers.ts b/ts/graphs/graph-helpers.ts index 64c1dcb12..f45786c0a 100644 --- a/ts/graphs/graph-helpers.ts +++ b/ts/graphs/graph-helpers.ts @@ -6,7 +6,7 @@ @typescript-eslint/no-explicit-any: "off", @typescript-eslint/ban-ts-comment: "off" */ -import type { Backend } from "lib/proto"; +import type { Backend, Cards } from "lib/proto"; import type { Selection } from "d3"; // amount of data to fetch from backend @@ -28,7 +28,7 @@ export enum GraphRange { } export interface GraphsContext { - cards: Backend.Card[]; + cards: Cards.Card[]; revlog: Backend.RevlogEntry[]; revlogRange: RevlogRange; nightMode: boolean; diff --git a/ts/graphs/intervals.ts b/ts/graphs/intervals.ts index 0f43715d0..27ae15da4 100644 --- a/ts/graphs/intervals.ts +++ b/ts/graphs/intervals.ts @@ -6,7 +6,7 @@ @typescript-eslint/no-explicit-any: "off", */ -import type { Backend } from "lib/proto"; +import type { Backend, Cards } from "lib/proto"; import { extent, histogram, @@ -37,7 +37,7 @@ export enum IntervalRange { } export function gatherIntervalData(data: Backend.GraphsResponse): IntervalGraphData { - const intervals = (data.cards as Backend.Card[]) + const intervals = (data.cards as Cards.Card[]) .filter((c) => [CardType.Review, CardType.Relearn].includes(c.ctype)) .map((c) => c.interval); return { intervals }; diff --git a/ts/lib/proto.ts b/ts/lib/proto.ts index 66d9033d4..c1a245585 100644 --- a/ts/lib/proto.ts +++ b/ts/lib/proto.ts @@ -3,4 +3,5 @@ import { anki } from "./backend_proto"; import Backend = anki.backend; -export { Backend }; +import Cards = anki.cards; +export { Backend, Cards };