From 35b059ecdb9b8d61285cb5801f384a0dc79eac45 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Sat, 10 Jul 2021 21:33:12 +1000 Subject: [PATCH] split out sync, search, scheduler & config --- proto/anki/backend.proto | 553 +---------------------------- proto/anki/configs.proto | 113 ++++++ proto/anki/scheduler.proto | 219 ++++++++++++ proto/anki/search.proto | 177 +++++++++ proto/anki/sync.proto | 76 ++++ pylib/anki/_backend/genbackend.py | 8 + pylib/anki/collection.py | 26 +- pylib/anki/config.py | 4 +- pylib/anki/configs_pb2.pyi | 1 + pylib/anki/deckconfig_pb2.pyi | 1 + pylib/anki/decks_pb2.pyi | 1 + pylib/anki/notes_pb2.pyi | 1 + pylib/anki/notetypes_pb2.pyi | 1 + pylib/anki/scheduler/base.py | 14 +- pylib/anki/scheduler/v2.py | 7 +- pylib/anki/scheduler/v3.py | 18 +- pylib/anki/scheduler_pb2.pyi | 1 + pylib/anki/search_pb2.pyi | 1 + pylib/anki/sync.py | 8 +- pylib/anki/sync_pb2.pyi | 1 + pylib/anki/syncserver/__init__.py | 2 +- rslib/src/backend/config.rs | 4 +- rslib/src/backend/mod.rs | 8 +- rslib/src/backend/scheduler/mod.rs | 4 +- rslib/src/backend_proto.rs | 16 +- ts/congrats/CongratsPage.svelte | 4 +- ts/congrats/lib.ts | 8 +- ts/lib/proto.ts | 3 +- ts/reviewer/answering.ts | 12 +- 29 files changed, 675 insertions(+), 617 deletions(-) create mode 100644 proto/anki/configs.proto create mode 100644 proto/anki/scheduler.proto create mode 100644 proto/anki/search.proto create mode 100644 proto/anki/sync.proto create mode 120000 pylib/anki/configs_pb2.pyi create mode 120000 pylib/anki/deckconfig_pb2.pyi create mode 120000 pylib/anki/decks_pb2.pyi create mode 120000 pylib/anki/notes_pb2.pyi create mode 120000 pylib/anki/notetypes_pb2.pyi create mode 120000 pylib/anki/scheduler_pb2.pyi create mode 120000 pylib/anki/search_pb2.pyi create mode 120000 pylib/anki/sync_pb2.pyi diff --git a/proto/anki/backend.proto b/proto/anki/backend.proto index 4d94e3481..7bcd88c6d 100644 --- a/proto/anki/backend.proto +++ b/proto/anki/backend.proto @@ -7,7 +7,6 @@ package anki.backend; import "anki/generic.proto"; import "anki/cards.proto"; -import "anki/decks.proto"; import "anki/collection.proto"; import "anki/notes.proto"; import "anki/notetypes.proto"; @@ -19,12 +18,12 @@ import "anki/notetypes.proto"; /// that information is not available in prost, so we define an enum to make /// sure all clients agree on the service index enum ServiceIndex { - SERVICE_INDEX_SCHEDULING = 0; + SERVICE_INDEX_SCHEDULER = 0; SERVICE_INDEX_DECKS = 1; SERVICE_INDEX_NOTES = 2; SERVICE_INDEX_SYNC = 3; SERVICE_INDEX_NOTETYPES = 4; - SERVICE_INDEX_CONFIG = 5; + SERVICE_INDEX_CONFIGS = 5; SERVICE_INDEX_CARD_RENDERING = 6; SERVICE_INDEX_DECK_CONFIG = 7; SERVICE_INDEX_TAGS = 8; @@ -36,61 +35,6 @@ enum ServiceIndex { SERVICE_INDEX_CARDS = 14; } -service SchedulingService { - rpc SchedTimingToday(generic.Empty) returns (SchedTimingTodayResponse); - rpc StudiedToday(generic.Empty) returns (generic.String); - rpc StudiedTodayMessage(StudiedTodayMessageRequest) returns (generic.String); - rpc UpdateStats(UpdateStatsRequest) returns (generic.Empty); - rpc ExtendLimits(ExtendLimitsRequest) returns (generic.Empty); - rpc CountsForDeckToday(decks.DeckId) returns (CountsForDeckTodayResponse); - rpc CongratsInfo(generic.Empty) returns (CongratsInfoResponse); - rpc RestoreBuriedAndSuspendedCards(cards.CardIds) - returns (collection.OpChanges); - rpc UnburyDeck(UnburyDeckRequest) returns (collection.OpChanges); - rpc BuryOrSuspendCards(BuryOrSuspendCardsRequest) - returns (collection.OpChangesWithCount); - rpc EmptyFilteredDeck(decks.DeckId) returns (collection.OpChanges); - rpc RebuildFilteredDeck(decks.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 (collection.OpChanges); - rpc UpgradeScheduler(generic.Empty) returns (generic.Empty); - rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards); -} - -service SyncService { - rpc SyncMedia(SyncAuth) returns (generic.Empty); - rpc AbortSync(generic.Empty) returns (generic.Empty); - rpc AbortMediaSync(generic.Empty) returns (generic.Empty); - rpc BeforeUpload(generic.Empty) returns (generic.Empty); - rpc SyncLogin(SyncLoginRequest) returns (SyncAuth); - rpc SyncStatus(SyncAuth) returns (SyncStatusResponse); - rpc SyncCollection(SyncAuth) returns (SyncCollectionResponse); - rpc FullUpload(SyncAuth) returns (generic.Empty); - rpc FullDownload(SyncAuth) returns (generic.Empty); - rpc SyncServerMethod(SyncServerMethodRequest) returns (generic.Json); -} - -service ConfigService { - rpc GetConfigJson(generic.String) returns (generic.Json); - rpc SetConfigJson(SetConfigJsonRequest) returns (collection.OpChanges); - rpc SetConfigJsonNoUndo(SetConfigJsonRequest) returns (generic.Empty); - 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 (collection.OpChanges); - rpc GetConfigString(Config.String) returns (generic.String); - rpc SetConfigString(SetConfigStringRequest) returns (collection.OpChanges); - rpc GetPreferences(generic.Empty) returns (Preferences); - rpc SetPreferences(Preferences) returns (collection.OpChanges); -} - service CardRenderingService { rpc ExtractAVTags(ExtractAVTagsRequest) returns (ExtractAVTagsResponse); rpc ExtractLatex(ExtractLatexRequest) returns (ExtractLatexResponse); @@ -121,19 +65,6 @@ service TagsService { returns (collection.OpChangesWithCount); } -service SearchService { - rpc BuildSearchString(SearchNode) returns (generic.String); - rpc SearchCards(SearchRequest) returns (SearchResponse); - rpc SearchNotes(SearchRequest) returns (SearchResponse); - rpc JoinSearchNodes(JoinSearchNodesRequest) returns (generic.String); - rpc ReplaceSearchNode(ReplaceSearchNodeRequest) returns (generic.String); - 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(cards.CardId) returns (generic.String); rpc Graphs(GraphsRequest) returns (GraphsResponse); @@ -194,11 +125,6 @@ message BackendError { // Messages /////////////////////////////////////////////////////////// -message SchedTimingTodayResponse { - uint32 days_elapsed = 1; - int64 next_day_at = 2; -} - message RenderExistingCardRequest { int64 card_id = 1; bool browser = 2; @@ -295,118 +221,11 @@ message TrashMediaFilesRequest { repeated string fnames = 1; } -message StudiedTodayMessageRequest { - uint32 cards = 1; - double seconds = 2; -} - message CongratsLearnMessageRequest { float next_due = 1; uint32 remaining = 2; } -message SearchRequest { - string search = 1; - SortOrder order = 2; -} - -message SearchResponse { - repeated int64 ids = 1; -} - -message SortOrder { - message Builtin { - string column = 1; - bool reverse = 2; - } - oneof value { - generic.Empty none = 1; - string custom = 2; - Builtin builtin = 3; - } -} - -message SearchNode { - message Dupe { - int64 notetype_id = 1; - string first_field = 2; - } - enum Flag { - FLAG_NONE = 0; - FLAG_ANY = 1; - FLAG_RED = 2; - FLAG_ORANGE = 3; - FLAG_GREEN = 4; - FLAG_BLUE = 5; - FLAG_PINK = 6; - FLAG_TURQUOISE = 7; - FLAG_PURPLE = 8; - } - enum Rating { - RATING_ANY = 0; - RATING_AGAIN = 1; - RATING_HARD = 2; - RATING_GOOD = 3; - RATING_EASY = 4; - RATING_BY_RESCHEDULE = 5; - } - message Rated { - uint32 days = 1; - Rating rating = 2; - } - enum CardState { - CARD_STATE_NEW = 0; - CARD_STATE_LEARN = 1; - CARD_STATE_REVIEW = 2; - CARD_STATE_DUE = 3; - CARD_STATE_SUSPENDED = 4; - CARD_STATE_BURIED = 5; - } - message IdList { - repeated int64 ids = 1; - } - message Group { - enum Joiner { - AND = 0; - OR = 1; - } - repeated SearchNode nodes = 1; - Joiner joiner = 2; - } - oneof filter { - Group group = 1; - SearchNode negated = 2; - string parsable_text = 3; - uint32 template = 4; - int64 nid = 5; - Dupe dupe = 6; - string field_name = 7; - Rated rated = 8; - uint32 added_in_days = 9; - int32 due_in_days = 10; - Flag flag = 11; - CardState card_state = 12; - IdList nids = 13; - uint32 edited_in_days = 14; - string deck = 15; - int32 due_on_day = 16; - string tag = 17; - string note = 18; - uint32 introduced_in_days = 19; - } -} - -message JoinSearchNodesRequest { - SearchNode.Group.Joiner joiner = 1; - SearchNode existing_node = 2; - SearchNode additional_node = 3; -} - -message ReplaceSearchNodeRequest { - SearchNode existing_node = 1; - SearchNode replacement_node = 2; -} - message SetTagCollapsedRequest { string name = 1; bool collapsed = 2; @@ -433,12 +252,6 @@ message RenameTagsRequest { string new_prefix = 2; } -message SetConfigJsonRequest { - string key = 1; - bytes value_json = 2; - bool undoable = 3; -} - message EmptyCardsReport { message NoteWithEmptyCards { int64 note_id = 1; @@ -449,59 +262,6 @@ message EmptyCardsReport { repeated NoteWithEmptyCards notes = 2; } -message FindAndReplaceRequest { - repeated int64 nids = 1; - string search = 2; - string replacement = 3; - bool regex = 4; - bool match_case = 5; - string field_name = 6; -} - -message BrowserColumns { - enum Sorting { - SORTING_NONE = 0; - SORTING_NORMAL = 1; - SORTING_REVERSED = 2; - } - enum Alignment { - ALIGNMENT_START = 0; - ALIGNMENT_CENTER = 1; - } - message Column { - string key = 1; - string cards_mode_label = 2; - string notes_mode_label = 3; - Sorting sorting = 4; - bool uses_cell_font = 5; - Alignment alignment = 6; - } - repeated Column columns = 1; -} - -message BrowserRow { - message Cell { - string text = 1; - bool is_rtl = 2; - } - enum Color { - COLOR_DEFAULT = 0; - COLOR_MARKED = 1; - COLOR_SUSPENDED = 2; - COLOR_FLAG_RED = 3; - COLOR_FLAG_ORANGE = 4; - COLOR_FLAG_GREEN = 5; - COLOR_FLAG_BLUE = 6; - COLOR_FLAG_PINK = 7; - COLOR_FLAG_TURQUOISE = 8; - COLOR_FLAG_PURPLE = 9; - } - repeated Cell cells = 1; - Color color = 2; - string font_name = 3; - uint32 font_size = 4; -} - message NoteIdsAndTagsRequest { repeated int64 note_ids = 1; string tags = 2; @@ -515,117 +275,6 @@ message FindAndReplaceTagRequest { bool match_case = 5; } -message Preferences { - message Scheduling { - enum NewReviewMix { - DISTRIBUTE = 0; - REVIEWS_FIRST = 1; - NEW_FIRST = 2; - } - - // read only; 1-3 - uint32 scheduler_version = 1; - - uint32 rollover = 2; - uint32 learn_ahead_secs = 3; - NewReviewMix new_review_mix = 4; - - // v2 only - bool new_timezone = 5; - bool day_learn_first = 6; - } - message Reviewing { - bool hide_audio_play_buttons = 1; - bool interrupt_audio_when_answering = 2; - bool show_remaining_due_counts = 3; - bool show_intervals_on_buttons = 4; - uint32 time_limit_secs = 5; - } - message Editing { - bool adding_defaults_to_current_deck = 1; - bool paste_images_as_png = 2; - bool paste_strips_formatting = 3; - string default_search_text = 4; - } - - Scheduling scheduling = 1; - Reviewing reviewing = 2; - Editing editing = 3; -} - -message SyncLoginRequest { - string username = 1; - string password = 2; -} - -message SyncStatusResponse { - enum Required { - NO_CHANGES = 0; - NORMAL_SYNC = 1; - FULL_SYNC = 2; - } - Required required = 1; -} - -message SyncCollectionResponse { - enum ChangesRequired { - NO_CHANGES = 0; - NORMAL_SYNC = 1; - FULL_SYNC = 2; - // local collection has no cards; upload not an option - FULL_DOWNLOAD = 3; - // remote collection has no cards; download not an option - FULL_UPLOAD = 4; - } - - uint32 host_number = 1; - string server_message = 2; - ChangesRequired required = 3; -} - -message SyncAuth { - string hkey = 1; - uint32 host_number = 2; -} - -message SyncServerMethodRequest { - enum Method { - HOST_KEY = 0; - META = 1; - START = 2; - APPLY_GRAVES = 3; - APPLY_CHANGES = 4; - CHUNK = 5; - APPLY_CHUNK = 6; - SANITY_CHECK = 7; - FINISH = 8; - ABORT = 9; - // caller must reopen after these two are called - FULL_UPLOAD = 10; - FULL_DOWNLOAD = 11; - } - Method method = 1; - bytes data = 2; -} - -message UpdateStatsRequest { - int64 deck_id = 1; - int32 new_delta = 2; - int32 review_delta = 4; - int32 millisecond_delta = 5; -} - -message ExtendLimitsRequest { - int64 deck_id = 1; - int32 new_delta = 2; - int32 review_delta = 3; -} - -message CountsForDeckTodayResponse { - int32 new = 1; - int32 review = 2; -} - message GraphsRequest { string search = 1; uint32 days = 2; @@ -673,205 +322,7 @@ message RevlogEntry { uint32 taken_millis = 8; ReviewKind review_kind = 9; } - -message CongratsInfoResponse { - uint32 learn_remaining = 1; - uint32 secs_until_next_learn = 2; - bool review_remaining = 3; - bool new_remaining = 4; - bool have_sched_buried = 5; - bool have_user_buried = 6; - bool is_filtered_deck = 7; - bool bridge_commands_supported = 8; - string deck_description = 9; -} - -message UnburyDeckRequest { - enum Mode { - ALL = 0; - SCHED_ONLY = 1; - USER_ONLY = 2; - } - int64 deck_id = 1; - Mode mode = 2; -} - -message BuryOrSuspendCardsRequest { - enum Mode { - SUSPEND = 0; - BURY_SCHED = 1; - BURY_USER = 2; - } - repeated int64 card_ids = 1; - repeated int64 note_ids = 2; - Mode mode = 3; -} - -message ScheduleCardsAsNewRequest { - repeated int64 card_ids = 1; - bool log = 2; -} - -message SetDueDateRequest { - repeated int64 card_ids = 1; - string days = 2; - Config.String config_key = 3; -} - -message SortCardsRequest { - repeated int64 card_ids = 1; - uint32 starting_from = 2; - uint32 step_size = 3; - bool randomize = 4; - bool shift_existing = 5; -} - -message SortDeckRequest { - int64 deck_id = 1; - bool randomize = 2; -} - -message Config { - message Bool { - enum Key { - BROWSER_TABLE_SHOW_NOTES_MODE = 0; - PREVIEW_BOTH_SIDES = 3; - COLLAPSE_TAGS = 4; - COLLAPSE_NOTETYPES = 5; - COLLAPSE_DECKS = 6; - COLLAPSE_SAVED_SEARCHES = 7; - COLLAPSE_TODAY = 8; - COLLAPSE_CARD_STATE = 9; - COLLAPSE_FLAGS = 10; - SCHED_2021 = 11; - ADDING_DEFAULTS_TO_CURRENT_DECK = 12; - HIDE_AUDIO_PLAY_BUTTONS = 13; - INTERRUPT_AUDIO_WHEN_ANSWERING = 14; - PASTE_IMAGES_AS_PNG = 15; - PASTE_STRIPS_FORMATTING = 16; - NORMALIZE_NOTE_TEXT = 17; - } - Key key = 1; - } - - message String { - enum Key { - SET_DUE_BROWSER = 0; - SET_DUE_REVIEWER = 1; - DEFAULT_SEARCH_TEXT = 2; - CARD_STATE_CUSTOMIZER = 3; - } - Key key = 1; - } -} - -message SetConfigBoolRequest { - Config.Bool.Key key = 1; - bool value = 2; - bool undoable = 3; -} - -message SetConfigStringRequest { - Config.String.Key key = 1; - string value = 2; - bool undoable = 3; -} - message RenderMarkdownRequest { string markdown = 1; bool sanitize = 2; } - -message SchedulingState { - message New { - uint32 position = 1; - } - message Learning { - uint32 remaining_steps = 1; - uint32 scheduled_secs = 2; - } - message Review { - uint32 scheduled_days = 1; - uint32 elapsed_days = 2; - float ease_factor = 3; - uint32 lapses = 4; - bool leeched = 5; - } - message Relearning { - Review review = 1; - Learning learning = 2; - } - message Normal { - oneof value { - New new = 1; - Learning learning = 2; - Review review = 3; - Relearning relearning = 4; - } - } - message Preview { - uint32 scheduled_secs = 1; - bool finished = 2; - } - message ReschedulingFilter { - Normal original_state = 1; - } - message Filtered { - oneof value { - Preview preview = 1; - ReschedulingFilter rescheduling = 2; - } - } - - oneof value { - Normal normal = 1; - Filtered filtered = 2; - } -} - -message NextCardStates { - SchedulingState current = 1; - SchedulingState again = 2; - SchedulingState hard = 3; - SchedulingState good = 4; - SchedulingState easy = 5; -} - -message CardAnswer { - enum Rating { - AGAIN = 0; - HARD = 1; - GOOD = 2; - EASY = 3; - } - - int64 card_id = 1; - SchedulingState current_state = 2; - SchedulingState new_state = 3; - Rating rating = 4; - int64 answered_at_millis = 5; - uint32 milliseconds_taken = 6; -} - -message GetQueuedCardsRequest { - uint32 fetch_limit = 1; - bool intraday_learning_only = 2; -} - -message QueuedCards { - enum Queue { - NEW = 0; - LEARNING = 1; - REVIEW = 2; - } - message QueuedCard { - cards.Card card = 1; - Queue queue = 2; - NextCardStates next_states = 3; - } - - repeated QueuedCard cards = 1; - uint32 new_count = 2; - uint32 learning_count = 3; - uint32 review_count = 4; -} diff --git a/proto/anki/configs.proto b/proto/anki/configs.proto new file mode 100644 index 000000000..3a7ed87bd --- /dev/null +++ b/proto/anki/configs.proto @@ -0,0 +1,113 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.configs; + +import "anki/generic.proto"; +import "anki/collection.proto"; + +service ConfigsService { + rpc GetConfigJson(generic.String) returns (generic.Json); + rpc SetConfigJson(SetConfigJsonRequest) returns (collection.OpChanges); + rpc SetConfigJsonNoUndo(SetConfigJsonRequest) returns (generic.Empty); + 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 (collection.OpChanges); + rpc GetConfigString(Config.String) returns (generic.String); + rpc SetConfigString(SetConfigStringRequest) returns (collection.OpChanges); + rpc GetPreferences(generic.Empty) returns (Preferences); + rpc SetPreferences(Preferences) returns (collection.OpChanges); +} + +message Config { + message Bool { + enum Key { + BROWSER_TABLE_SHOW_NOTES_MODE = 0; + PREVIEW_BOTH_SIDES = 3; + COLLAPSE_TAGS = 4; + COLLAPSE_NOTETYPES = 5; + COLLAPSE_DECKS = 6; + COLLAPSE_SAVED_SEARCHES = 7; + COLLAPSE_TODAY = 8; + COLLAPSE_CARD_STATE = 9; + COLLAPSE_FLAGS = 10; + SCHED_2021 = 11; + ADDING_DEFAULTS_TO_CURRENT_DECK = 12; + HIDE_AUDIO_PLAY_BUTTONS = 13; + INTERRUPT_AUDIO_WHEN_ANSWERING = 14; + PASTE_IMAGES_AS_PNG = 15; + PASTE_STRIPS_FORMATTING = 16; + NORMALIZE_NOTE_TEXT = 17; + } + Key key = 1; + } + + message String { + enum Key { + SET_DUE_BROWSER = 0; + SET_DUE_REVIEWER = 1; + DEFAULT_SEARCH_TEXT = 2; + CARD_STATE_CUSTOMIZER = 3; + } + Key key = 1; + } +} + +message SetConfigBoolRequest { + Config.Bool.Key key = 1; + bool value = 2; + bool undoable = 3; +} + +message SetConfigStringRequest { + Config.String.Key key = 1; + string value = 2; + bool undoable = 3; +} + +message SetConfigJsonRequest { + string key = 1; + bytes value_json = 2; + bool undoable = 3; +} + +message Preferences { + message Scheduling { + enum NewReviewMix { + DISTRIBUTE = 0; + REVIEWS_FIRST = 1; + NEW_FIRST = 2; + } + + // read only; 1-3 + uint32 scheduler_version = 1; + + uint32 rollover = 2; + uint32 learn_ahead_secs = 3; + NewReviewMix new_review_mix = 4; + + // v2 only + bool new_timezone = 5; + bool day_learn_first = 6; + } + message Reviewing { + bool hide_audio_play_buttons = 1; + bool interrupt_audio_when_answering = 2; + bool show_remaining_due_counts = 3; + bool show_intervals_on_buttons = 4; + uint32 time_limit_secs = 5; + } + message Editing { + bool adding_defaults_to_current_deck = 1; + bool paste_images_as_png = 2; + bool paste_strips_formatting = 3; + string default_search_text = 4; + } + + Scheduling scheduling = 1; + Reviewing reviewing = 2; + Editing editing = 3; +} diff --git a/proto/anki/scheduler.proto b/proto/anki/scheduler.proto new file mode 100644 index 000000000..d7d27b444 --- /dev/null +++ b/proto/anki/scheduler.proto @@ -0,0 +1,219 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.scheduler; + +import "anki/generic.proto"; +import "anki/cards.proto"; +import "anki/decks.proto"; +import "anki/collection.proto"; +import "anki/configs.proto"; + +service SchedulerService { + rpc GetQueuedCards(GetQueuedCardsRequest) returns (QueuedCards); + rpc AnswerCard(CardAnswer) returns (collection.OpChanges); + rpc SchedTimingToday(generic.Empty) returns (SchedTimingTodayResponse); + rpc StudiedToday(generic.Empty) returns (generic.String); + rpc StudiedTodayMessage(StudiedTodayMessageRequest) returns (generic.String); + rpc UpdateStats(UpdateStatsRequest) returns (generic.Empty); + rpc ExtendLimits(ExtendLimitsRequest) returns (generic.Empty); + rpc CountsForDeckToday(decks.DeckId) returns (CountsForDeckTodayResponse); + rpc CongratsInfo(generic.Empty) returns (CongratsInfoResponse); + rpc RestoreBuriedAndSuspendedCards(cards.CardIds) + returns (collection.OpChanges); + rpc UnburyDeck(UnburyDeckRequest) returns (collection.OpChanges); + rpc BuryOrSuspendCards(BuryOrSuspendCardsRequest) + returns (collection.OpChangesWithCount); + rpc EmptyFilteredDeck(decks.DeckId) returns (collection.OpChanges); + rpc RebuildFilteredDeck(decks.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 UpgradeScheduler(generic.Empty) returns (generic.Empty); +} + +message SchedulingState { + message New { + uint32 position = 1; + } + message Learning { + uint32 remaining_steps = 1; + uint32 scheduled_secs = 2; + } + message Review { + uint32 scheduled_days = 1; + uint32 elapsed_days = 2; + float ease_factor = 3; + uint32 lapses = 4; + bool leeched = 5; + } + message Relearning { + Review review = 1; + Learning learning = 2; + } + message Normal { + oneof value { + New new = 1; + Learning learning = 2; + Review review = 3; + Relearning relearning = 4; + } + } + message Preview { + uint32 scheduled_secs = 1; + bool finished = 2; + } + message ReschedulingFilter { + Normal original_state = 1; + } + message Filtered { + oneof value { + Preview preview = 1; + ReschedulingFilter rescheduling = 2; + } + } + + oneof value { + Normal normal = 1; + Filtered filtered = 2; + } +} + +message QueuedCards { + enum Queue { + NEW = 0; + LEARNING = 1; + REVIEW = 2; + } + message QueuedCard { + cards.Card card = 1; + Queue queue = 2; + NextCardStates next_states = 3; + } + + repeated QueuedCard cards = 1; + uint32 new_count = 2; + uint32 learning_count = 3; + uint32 review_count = 4; +} + +message GetQueuedCardsRequest { + uint32 fetch_limit = 1; + bool intraday_learning_only = 2; +} + +message SchedTimingTodayResponse { + uint32 days_elapsed = 1; + int64 next_day_at = 2; +} + +message StudiedTodayMessageRequest { + uint32 cards = 1; + double seconds = 2; +} + +message UpdateStatsRequest { + int64 deck_id = 1; + int32 new_delta = 2; + int32 review_delta = 4; + int32 millisecond_delta = 5; +} + +message ExtendLimitsRequest { + int64 deck_id = 1; + int32 new_delta = 2; + int32 review_delta = 3; +} + +message CountsForDeckTodayResponse { + int32 new = 1; + int32 review = 2; +} + +message CongratsInfoResponse { + uint32 learn_remaining = 1; + uint32 secs_until_next_learn = 2; + bool review_remaining = 3; + bool new_remaining = 4; + bool have_sched_buried = 5; + bool have_user_buried = 6; + bool is_filtered_deck = 7; + bool bridge_commands_supported = 8; + string deck_description = 9; +} + +message UnburyDeckRequest { + enum Mode { + ALL = 0; + SCHED_ONLY = 1; + USER_ONLY = 2; + } + int64 deck_id = 1; + Mode mode = 2; +} + +message BuryOrSuspendCardsRequest { + enum Mode { + SUSPEND = 0; + BURY_SCHED = 1; + BURY_USER = 2; + } + repeated int64 card_ids = 1; + repeated int64 note_ids = 2; + Mode mode = 3; +} + +message ScheduleCardsAsNewRequest { + repeated int64 card_ids = 1; + bool log = 2; +} + +message SetDueDateRequest { + repeated int64 card_ids = 1; + string days = 2; + configs.Config.String config_key = 3; +} + +message SortCardsRequest { + repeated int64 card_ids = 1; + uint32 starting_from = 2; + uint32 step_size = 3; + bool randomize = 4; + bool shift_existing = 5; +} + +message SortDeckRequest { + int64 deck_id = 1; + bool randomize = 2; +} + +message NextCardStates { + SchedulingState current = 1; + SchedulingState again = 2; + SchedulingState hard = 3; + SchedulingState good = 4; + SchedulingState easy = 5; +} + +message CardAnswer { + enum Rating { + AGAIN = 0; + HARD = 1; + GOOD = 2; + EASY = 3; + } + + int64 card_id = 1; + SchedulingState current_state = 2; + SchedulingState new_state = 3; + Rating rating = 4; + int64 answered_at_millis = 5; + uint32 milliseconds_taken = 6; +} diff --git a/proto/anki/search.proto b/proto/anki/search.proto new file mode 100644 index 000000000..91a7d9148 --- /dev/null +++ b/proto/anki/search.proto @@ -0,0 +1,177 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.search; + +import "anki/generic.proto"; +import "anki/collection.proto"; + +service SearchService { + rpc BuildSearchString(SearchNode) returns (generic.String); + rpc SearchCards(SearchRequest) returns (SearchResponse); + rpc SearchNotes(SearchRequest) returns (SearchResponse); + rpc JoinSearchNodes(JoinSearchNodesRequest) returns (generic.String); + rpc ReplaceSearchNode(ReplaceSearchNodeRequest) returns (generic.String); + 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); +} + +message SearchNode { + message Dupe { + int64 notetype_id = 1; + string first_field = 2; + } + enum Flag { + FLAG_NONE = 0; + FLAG_ANY = 1; + FLAG_RED = 2; + FLAG_ORANGE = 3; + FLAG_GREEN = 4; + FLAG_BLUE = 5; + FLAG_PINK = 6; + FLAG_TURQUOISE = 7; + FLAG_PURPLE = 8; + } + enum Rating { + RATING_ANY = 0; + RATING_AGAIN = 1; + RATING_HARD = 2; + RATING_GOOD = 3; + RATING_EASY = 4; + RATING_BY_RESCHEDULE = 5; + } + message Rated { + uint32 days = 1; + Rating rating = 2; + } + enum CardState { + CARD_STATE_NEW = 0; + CARD_STATE_LEARN = 1; + CARD_STATE_REVIEW = 2; + CARD_STATE_DUE = 3; + CARD_STATE_SUSPENDED = 4; + CARD_STATE_BURIED = 5; + } + message IdList { + repeated int64 ids = 1; + } + message Group { + enum Joiner { + AND = 0; + OR = 1; + } + repeated SearchNode nodes = 1; + Joiner joiner = 2; + } + oneof filter { + Group group = 1; + SearchNode negated = 2; + string parsable_text = 3; + uint32 template = 4; + int64 nid = 5; + Dupe dupe = 6; + string field_name = 7; + Rated rated = 8; + uint32 added_in_days = 9; + int32 due_in_days = 10; + Flag flag = 11; + CardState card_state = 12; + IdList nids = 13; + uint32 edited_in_days = 14; + string deck = 15; + int32 due_on_day = 16; + string tag = 17; + string note = 18; + uint32 introduced_in_days = 19; + } +} + +message SearchRequest { + string search = 1; + SortOrder order = 2; +} + +message SearchResponse { + repeated int64 ids = 1; +} + +message SortOrder { + message Builtin { + string column = 1; + bool reverse = 2; + } + oneof value { + generic.Empty none = 1; + string custom = 2; + Builtin builtin = 3; + } +} + +message JoinSearchNodesRequest { + SearchNode.Group.Joiner joiner = 1; + SearchNode existing_node = 2; + SearchNode additional_node = 3; +} + +message ReplaceSearchNodeRequest { + SearchNode existing_node = 1; + SearchNode replacement_node = 2; +} + +message FindAndReplaceRequest { + repeated int64 nids = 1; + string search = 2; + string replacement = 3; + bool regex = 4; + bool match_case = 5; + string field_name = 6; +} + +message BrowserColumns { + enum Sorting { + SORTING_NONE = 0; + SORTING_NORMAL = 1; + SORTING_REVERSED = 2; + } + enum Alignment { + ALIGNMENT_START = 0; + ALIGNMENT_CENTER = 1; + } + message Column { + string key = 1; + string cards_mode_label = 2; + string notes_mode_label = 3; + Sorting sorting = 4; + bool uses_cell_font = 5; + Alignment alignment = 6; + } + repeated Column columns = 1; +} + +message BrowserRow { + message Cell { + string text = 1; + bool is_rtl = 2; + } + enum Color { + COLOR_DEFAULT = 0; + COLOR_MARKED = 1; + COLOR_SUSPENDED = 2; + COLOR_FLAG_RED = 3; + COLOR_FLAG_ORANGE = 4; + COLOR_FLAG_GREEN = 5; + COLOR_FLAG_BLUE = 6; + COLOR_FLAG_PINK = 7; + COLOR_FLAG_TURQUOISE = 8; + COLOR_FLAG_PURPLE = 9; + } + repeated Cell cells = 1; + Color color = 2; + string font_name = 3; + uint32 font_size = 4; +} diff --git a/proto/anki/sync.proto b/proto/anki/sync.proto new file mode 100644 index 000000000..67553884f --- /dev/null +++ b/proto/anki/sync.proto @@ -0,0 +1,76 @@ +// Copyright: Ankitects Pty Ltd and contributors +// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html + +syntax = "proto3"; + +package anki.sync; + +import "anki/generic.proto"; + +service SyncService { + rpc SyncMedia(SyncAuth) returns (generic.Empty); + rpc AbortSync(generic.Empty) returns (generic.Empty); + rpc AbortMediaSync(generic.Empty) returns (generic.Empty); + rpc BeforeUpload(generic.Empty) returns (generic.Empty); + rpc SyncLogin(SyncLoginRequest) returns (SyncAuth); + rpc SyncStatus(SyncAuth) returns (SyncStatusResponse); + rpc SyncCollection(SyncAuth) returns (SyncCollectionResponse); + rpc FullUpload(SyncAuth) returns (generic.Empty); + rpc FullDownload(SyncAuth) returns (generic.Empty); + rpc SyncServerMethod(SyncServerMethodRequest) returns (generic.Json); +} + +message SyncAuth { + string hkey = 1; + uint32 host_number = 2; +} + +message SyncLoginRequest { + string username = 1; + string password = 2; +} + +message SyncStatusResponse { + enum Required { + NO_CHANGES = 0; + NORMAL_SYNC = 1; + FULL_SYNC = 2; + } + Required required = 1; +} + +message SyncCollectionResponse { + enum ChangesRequired { + NO_CHANGES = 0; + NORMAL_SYNC = 1; + FULL_SYNC = 2; + // local collection has no cards; upload not an option + FULL_DOWNLOAD = 3; + // remote collection has no cards; download not an option + FULL_UPLOAD = 4; + } + + uint32 host_number = 1; + string server_message = 2; + ChangesRequired required = 3; +} + +message SyncServerMethodRequest { + enum Method { + HOST_KEY = 0; + META = 1; + START = 2; + APPLY_GRAVES = 3; + APPLY_CHANGES = 4; + CHUNK = 5; + APPLY_CHUNK = 6; + SANITY_CHECK = 7; + FINISH = 8; + ABORT = 9; + // caller must reopen after these two are called + FULL_UPLOAD = 10; + FULL_DOWNLOAD = 11; + } + Method method = 1; + bytes data = 2; +} diff --git a/pylib/anki/_backend/genbackend.py b/pylib/anki/_backend/genbackend.py index cbe84735c..ce8310676 100755 --- a/pylib/anki/_backend/genbackend.py +++ b/pylib/anki/_backend/genbackend.py @@ -16,6 +16,10 @@ import anki.decks_pb2 import anki.deckconfig_pb2 import anki.notes_pb2 import anki.notetypes_pb2 +import anki.scheduler_pb2 +import anki.sync_pb2 +import anki.configs_pb2 +import anki.search_pb2 import stringcase @@ -179,6 +183,10 @@ service_modules = dict( DECKS=anki.decks_pb2, DECK_CONFIG=anki.deckconfig_pb2, NOTETYPES=anki.notetypes_pb2, + SCHEDULER=anki.scheduler_pb2, + SYNC=anki.sync_pb2, + CONFIGS=anki.configs_pb2, + SEARCH=anki.search_pb2, ) for service in anki.backend_pb2.ServiceIndex.DESCRIPTOR.values: diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index 7821a180d..e30d95362 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -8,22 +8,22 @@ from __future__ import annotations from typing import Any, Generator, List, Literal, Optional, Sequence, Tuple, Union, cast import anki.backend_pb2 as _pb -from anki import collection_pb2 +from anki import collection_pb2, configs_pb2, generic_pb2, search_pb2 from anki._legacy import DeprecatedNamesMixin, deprecated # protobuf we publicly export - listed first to avoid circular imports -SearchNode = _pb.SearchNode +SearchNode = search_pb2.SearchNode Progress = collection_pb2.Progress EmptyCardsReport = _pb.EmptyCardsReport GraphPreferences = _pb.GraphPreferences -Preferences = _pb.Preferences +Preferences = configs_pb2.Preferences UndoStatus = collection_pb2.UndoStatus OpChanges = collection_pb2.OpChanges OpChangesWithCount = collection_pb2.OpChangesWithCount OpChangesWithId = collection_pb2.OpChangesWithId OpChangesAfterUndo = collection_pb2.OpChangesAfterUndo -BrowserRow = _pb.BrowserRow -BrowserColumns = _pb.BrowserColumns +BrowserRow = search_pb2.BrowserRow +BrowserColumns = search_pb2.BrowserColumns import copy import os @@ -34,7 +34,7 @@ import weakref from dataclasses import dataclass, field import anki.latex -from anki import generic_pb2, hooks +from anki import hooks from anki._backend import RustBackend, Translations from anki.browser import BrowserConfig, BrowserDefaults from anki.cards import Card, CardId @@ -486,12 +486,12 @@ class Collection(DeprecatedNamesMixin): order: Union[bool, str, BrowserColumns.Column], reverse: bool, finding_notes: bool, - ) -> _pb.SortOrder: + ) -> search_pb2.SortOrder: if isinstance(order, str): - return _pb.SortOrder(custom=order) + return search_pb2.SortOrder(custom=order) if isinstance(order, bool): if order is False: - return _pb.SortOrder(none=generic_pb2.Empty()) + return search_pb2.SortOrder(none=generic_pb2.Empty()) # order=True: set args to sort column and reverse from config sort_key = BrowserConfig.sort_column_key(finding_notes) order = self.get_browser_column(self.get_config(sort_key)) @@ -499,13 +499,15 @@ class Collection(DeprecatedNamesMixin): reverse = self.get_config(reverse_key) if isinstance(order, BrowserColumns.Column): if order.sorting != BrowserColumns.SORTING_NONE: - return _pb.SortOrder( - builtin=_pb.SortOrder.Builtin(column=order.key, reverse=reverse) + return search_pb2.SortOrder( + builtin=search_pb2.SortOrder.Builtin( + column=order.key, reverse=reverse + ) ) # eg, user is ordering on an add-on field with the add-on not installed print(f"{order} is not a valid sort order.") - return _pb.SortOrder(none=generic_pb2.Empty()) + return search_pb2.SortOrder(none=generic_pb2.Empty()) def find_and_replace( self, diff --git a/pylib/anki/config.py b/pylib/anki/config.py index 0ed79f085..bd3de9219 100644 --- a/pylib/anki/config.py +++ b/pylib/anki/config.py @@ -25,12 +25,12 @@ from typing import Any from weakref import ref import anki -from anki import backend_pb2 as _pb +from anki import configs_pb2 from anki.collection import OpChanges from anki.errors import NotFoundError from anki.utils import from_json_bytes, to_json_bytes -Config = _pb.Config +Config = configs_pb2.Config class ConfigManager: diff --git a/pylib/anki/configs_pb2.pyi b/pylib/anki/configs_pb2.pyi new file mode 120000 index 000000000..a32f273c0 --- /dev/null +++ b/pylib/anki/configs_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/configs_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/deckconfig_pb2.pyi b/pylib/anki/deckconfig_pb2.pyi new file mode 120000 index 000000000..9cd723191 --- /dev/null +++ b/pylib/anki/deckconfig_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/deckconfig_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/decks_pb2.pyi b/pylib/anki/decks_pb2.pyi new file mode 120000 index 000000000..dc097aa9f --- /dev/null +++ b/pylib/anki/decks_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/decks_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/notes_pb2.pyi b/pylib/anki/notes_pb2.pyi new file mode 120000 index 000000000..3728ff344 --- /dev/null +++ b/pylib/anki/notes_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/notes_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/notetypes_pb2.pyi b/pylib/anki/notetypes_pb2.pyi new file mode 120000 index 000000000..7d08b284d --- /dev/null +++ b/pylib/anki/notetypes_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/notetypes_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/scheduler/base.py b/pylib/anki/scheduler/base.py index 0f602b831..9ce53f157 100644 --- a/pylib/anki/scheduler/base.py +++ b/pylib/anki/scheduler/base.py @@ -4,12 +4,15 @@ from __future__ import annotations import anki -import anki.backend_pb2 as _pb -from anki import decks_pb2 +from anki import decks_pb2, scheduler_pb2 from anki.collection import OpChanges, OpChangesWithCount, OpChangesWithId from anki.config import Config -SchedTimingToday = _pb.SchedTimingTodayResponse +SchedTimingToday = scheduler_pb2.SchedTimingTodayResponse +CongratsInfo = scheduler_pb2.CongratsInfoResponse +UnburyDeck = scheduler_pb2.UnburyDeckRequest +BuryOrSuspend = scheduler_pb2.BuryOrSuspendCardsRequest +FilteredDeckForUpdate = decks_pb2.FilteredDeckForUpdate from typing import List, Optional, Sequence @@ -20,11 +23,6 @@ from anki.decks import DeckConfigDict, DeckId, DeckTreeNode from anki.notes import NoteId from anki.utils import ids2str, intTime -CongratsInfo = _pb.CongratsInfoResponse -UnburyDeck = _pb.UnburyDeckRequest -BuryOrSuspend = _pb.BuryOrSuspendCardsRequest -FilteredDeckForUpdate = decks_pb2.FilteredDeckForUpdate - class SchedulerBase: "Actions shared between schedulers." diff --git a/pylib/anki/scheduler/v2.py b/pylib/anki/scheduler/v2.py index 9c32366eb..43500c4c1 100644 --- a/pylib/anki/scheduler/v2.py +++ b/pylib/anki/scheduler/v2.py @@ -11,8 +11,7 @@ from heapq import * from typing import Any, Callable, Dict, List, Optional, Tuple, Union import anki # pylint: disable=unused-import -import anki.backend_pb2 as _pb -from anki import hooks +from anki import hooks, scheduler_pb2 from anki.cards import Card, CardId from anki.consts import * from anki.decks import DeckConfigDict, DeckDict, DeckId @@ -20,8 +19,8 @@ from anki.lang import FormatTimeSpan from anki.scheduler.legacy import SchedulerBaseWithLegacy from anki.utils import ids2str, intTime -CountsForDeckToday = _pb.CountsForDeckTodayResponse -SchedTimingToday = _pb.SchedTimingTodayResponse +CountsForDeckToday = scheduler_pb2.CountsForDeckTodayResponse +SchedTimingToday = scheduler_pb2.SchedTimingTodayResponse # legacy type alias QueueConfig = Dict[str, Any] diff --git a/pylib/anki/scheduler/v3.py b/pylib/anki/scheduler/v3.py index da84b6118..60463dbce 100644 --- a/pylib/anki/scheduler/v3.py +++ b/pylib/anki/scheduler/v3.py @@ -14,7 +14,7 @@ from __future__ import annotations from typing import List, Literal, Sequence, Tuple -import anki.backend_pb2 as _pb +from anki import scheduler_pb2 from anki.cards import Card from anki.collection import OpChanges from anki.consts import * @@ -24,10 +24,10 @@ from anki.scheduler.legacy import SchedulerBaseWithLegacy from anki.types import assert_exhaustive from anki.utils import intTime -QueuedCards = _pb.QueuedCards -SchedulingState = _pb.SchedulingState -NextStates = _pb.NextCardStates -CardAnswer = _pb.CardAnswer +QueuedCards = scheduler_pb2.QueuedCards +SchedulingState = scheduler_pb2.SchedulingState +NextStates = scheduler_pb2.NextCardStates +CardAnswer = scheduler_pb2.CardAnswer class Scheduler(SchedulerBaseWithLegacy): @@ -171,7 +171,7 @@ class Scheduler(SchedulerBaseWithLegacy): ########################################################################## # fixme: move these into tests_schedv2 in the future - def _interval_for_state(self, state: _pb.SchedulingState) -> int: + def _interval_for_state(self, state: scheduler_pb2.SchedulingState) -> int: kind = state.WhichOneof("value") if kind == "normal": return self._interval_for_normal_state(state.normal) @@ -181,7 +181,9 @@ class Scheduler(SchedulerBaseWithLegacy): assert_exhaustive(kind) return 0 # unreachable - def _interval_for_normal_state(self, normal: _pb.SchedulingState.Normal) -> int: + def _interval_for_normal_state( + self, normal: scheduler_pb2.SchedulingState.Normal + ) -> int: kind = normal.WhichOneof("value") if kind == "new": return 0 @@ -196,7 +198,7 @@ class Scheduler(SchedulerBaseWithLegacy): return 0 # unreachable def _interval_for_filtered_state( - self, filtered: _pb.SchedulingState.Filtered + self, filtered: scheduler_pb2.SchedulingState.Filtered ) -> int: kind = filtered.WhichOneof("value") if kind == "preview": diff --git a/pylib/anki/scheduler_pb2.pyi b/pylib/anki/scheduler_pb2.pyi new file mode 120000 index 000000000..c09399793 --- /dev/null +++ b/pylib/anki/scheduler_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/scheduler_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/search_pb2.pyi b/pylib/anki/search_pb2.pyi new file mode 120000 index 000000000..5161a8d44 --- /dev/null +++ b/pylib/anki/search_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/search_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/sync.py b/pylib/anki/sync.py index 54c2196d6..e52611d30 100644 --- a/pylib/anki/sync.py +++ b/pylib/anki/sync.py @@ -1,12 +1,12 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -import anki.backend_pb2 as _pb +from anki import sync_pb2 # public exports -SyncAuth = _pb.SyncAuth -SyncOutput = _pb.SyncCollectionResponse -SyncStatus = _pb.SyncStatusResponse +SyncAuth = sync_pb2.SyncAuth +SyncOutput = sync_pb2.SyncCollectionResponse +SyncStatus = sync_pb2.SyncStatusResponse # Legacy attributes some add-ons may be using diff --git a/pylib/anki/sync_pb2.pyi b/pylib/anki/sync_pb2.pyi new file mode 120000 index 000000000..c6c8de862 --- /dev/null +++ b/pylib/anki/sync_pb2.pyi @@ -0,0 +1 @@ +../../bazel-bin/pylib/anki/sync_pb2.pyi \ No newline at end of file diff --git a/pylib/anki/syncserver/__init__.py b/pylib/anki/syncserver/__init__.py index 48da5dd1c..fc7690bb0 100644 --- a/pylib/anki/syncserver/__init__.py +++ b/pylib/anki/syncserver/__init__.py @@ -27,7 +27,7 @@ except ImportError as e: from flask import Response from anki import Collection -from anki.backend_pb2 import SyncServerMethodRequest +from anki.sync_pb2 import SyncServerMethodRequest Method = SyncServerMethodRequest.Method # pylint: disable=no-member diff --git a/rslib/src/backend/config.rs b/rslib/src/backend/config.rs index e4c2222da..72d0dea63 100644 --- a/rslib/src/backend/config.rs +++ b/rslib/src/backend/config.rs @@ -4,7 +4,7 @@ use serde_json::Value; use super::Backend; -pub(super) use crate::backend_proto::config_service::Service as ConfigService; +pub(super) use crate::backend_proto::configs_service::Service as ConfigsService; use crate::{ backend_proto as pb, backend_proto::config::{bool::Key as BoolKeyProto, string::Key as StringKeyProto}, @@ -52,7 +52,7 @@ impl From for StringKey { } } -impl ConfigService for Backend { +impl ConfigsService for Backend { fn get_config_json(&self, input: pb::String) -> Result { self.with_col(|col| { let val: Option = col.get_config_optional(input.val.as_str()); diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index 074ee23a7..e6c5daa2d 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -40,7 +40,7 @@ use self::{ card::CardsService, cardrendering::CardRenderingService, collection::CollectionService, - config::ConfigService, + config::ConfigsService, deckconfig::DeckConfigService, decks::DecksService, i18n::I18nService, @@ -48,7 +48,7 @@ use self::{ notes::NotesService, notetypes::NotetypesService, progress::ProgressState, - scheduler::SchedulingService, + scheduler::SchedulerService, search::SearchService, stats::StatsService, sync::{SyncService, SyncState}, @@ -117,11 +117,11 @@ impl Backend { pb::ServiceIndex::from_i32(service as i32) .ok_or_else(|| AnkiError::invalid_input("invalid service")) .and_then(|service| match service { - pb::ServiceIndex::Scheduling => SchedulingService::run_method(self, method, input), + pb::ServiceIndex::Scheduler => SchedulerService::run_method(self, method, input), pb::ServiceIndex::Decks => DecksService::run_method(self, method, input), pb::ServiceIndex::Notes => NotesService::run_method(self, method, input), pb::ServiceIndex::Notetypes => NotetypesService::run_method(self, method, input), - pb::ServiceIndex::Config => ConfigService::run_method(self, method, input), + pb::ServiceIndex::Configs => ConfigsService::run_method(self, method, input), pb::ServiceIndex::Sync => SyncService::run_method(self, method, input), pb::ServiceIndex::Tags => TagsService::run_method(self, method, input), pb::ServiceIndex::DeckConfig => DeckConfigService::run_method(self, method, input), diff --git a/rslib/src/backend/scheduler/mod.rs b/rslib/src/backend/scheduler/mod.rs index 176a0d12c..11d6d468d 100644 --- a/rslib/src/backend/scheduler/mod.rs +++ b/rslib/src/backend/scheduler/mod.rs @@ -5,7 +5,7 @@ mod answering; mod states; use super::Backend; -pub(super) use crate::backend_proto::scheduling_service::Service as SchedulingService; +pub(super) use crate::backend_proto::scheduler_service::Service as SchedulerService; use crate::{ backend_proto::{self as pb}, prelude::*, @@ -16,7 +16,7 @@ use crate::{ stats::studied_today, }; -impl SchedulingService for Backend { +impl SchedulerService for Backend { /// This behaves like _updateCutoff() in older code - it also unburies at the start of /// a new day. fn sched_timing_today(&self, _input: pb::Empty) -> Result { diff --git a/rslib/src/backend_proto.rs b/rslib/src/backend_proto.rs index 43ce3c497..9b169547a 100644 --- a/rslib/src/backend_proto.rs +++ b/rslib/src/backend_proto.rs @@ -14,11 +14,15 @@ macro_rules! protobuf { } protobuf!(backend); +protobuf!(cards); +protobuf!(collection); +protobuf!(configs); +protobuf!(deckconfig); +protobuf!(decks); +protobuf!(generic); +protobuf!(i18n); protobuf!(notes); protobuf!(notetypes); -protobuf!(decks); -protobuf!(deckconfig); -protobuf!(i18n); -protobuf!(cards); -protobuf!(generic); -protobuf!(collection); +protobuf!(scheduler); +protobuf!(search); +protobuf!(sync); diff --git a/ts/congrats/CongratsPage.svelte b/ts/congrats/CongratsPage.svelte index d0c9d8492..122d42cb8 100644 --- a/ts/congrats/CongratsPage.svelte +++ b/ts/congrats/CongratsPage.svelte @@ -3,11 +3,11 @@ Copyright: Ankitects Pty Ltd and contributors License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html -->