Fix undo of methods returning OpChanges directly not being handled correctly

This commit is contained in:
Abdo 2025-10-15 00:45:52 +03:00
parent d0eb61acdb
commit 9b28ed87f2
3 changed files with 34 additions and 20 deletions

View file

@ -999,8 +999,13 @@ def raw_backend_request(endpoint: str) -> Callable[[], bytes]:
def wrapped() -> bytes:
output = getattr(aqt.mw.col._backend, f"{endpoint}_raw")(request.data)
if "Has-Op-Changes" in request.headers:
response = OpChangesOnly()
op_changes_type = int(request.headers.get("Anki-Op-Changes", "0"))
if op_changes_type:
response: OpChanges | OpChangesOnly
if op_changes_type == 1:
response = OpChanges()
else:
response = OpChangesOnly()
response.ParseFromString(output)
def handle_on_main() -> None:

View file

@ -74,15 +74,16 @@ fn write_ts_method(
input_type,
output_type,
comments,
has_op_changes,
op_changes_type,
}: &MethodDetails,
out: &mut String,
) {
let op_changes_type = *op_changes_type as u8;
let comments = format_comments(comments);
writeln!(
out,
r#"{comments}export async function {method_name}(input: PlainMessage<{input_type}>, options?: PostProtoOptions): Promise<{output_type}> {{
return await postProto("{method_name}", new {input_type}(input), {output_type}, options, {has_op_changes});
return await postProto("{method_name}", new {input_type}(input), {output_type}, options, {op_changes_type});
}}"#
).unwrap()
}
@ -94,12 +95,20 @@ fn format_comments(comments: &Option<String>) -> String {
.unwrap_or_default()
}
#[derive(Clone, Copy)]
#[repr(u8)]
enum OpChangesType {
None = 0,
OpChanges = 1,
OpChangesOnly = 2,
}
struct MethodDetails {
method_name: String,
input_type: String,
output_type: String,
comments: Option<String>,
has_op_changes: bool,
op_changes_type: OpChangesType,
}
impl MethodDetails {
@ -108,28 +117,32 @@ impl MethodDetails {
let input_type = full_name_to_imported_reference(method.proto.input().full_name());
let output_type = full_name_to_imported_reference(method.proto.output().full_name());
let comments = method.comments.clone();
let has_op_changes = has_op_changes(&method.proto.output());
let op_changes_type = get_op_changes_type(&method.proto.output(), true);
Self {
method_name: name,
input_type,
output_type,
comments,
has_op_changes,
op_changes_type,
}
}
}
fn has_op_changes(message: &MessageDescriptor) -> bool {
fn get_op_changes_type(message: &MessageDescriptor, root: bool) -> OpChangesType {
if message.full_name() == "anki.collection.OpChanges" {
true
if root {
OpChangesType::OpChanges
} else {
OpChangesType::OpChangesOnly
}
} else if let Some(field) = message.get_field(1) {
if let Some(field_message) = field.kind().as_message() {
has_op_changes(field_message)
get_op_changes_type(field_message, false)
} else {
false
OpChangesType::None
}
} else {
false
OpChangesType::None
}
}

View file

@ -11,12 +11,12 @@ export async function postProto<T>(
input: { toBinary(): Uint8Array; getType(): { typeName: string } },
outputType: { fromBinary(arr: Uint8Array): T },
options: PostProtoOptions = {},
hasOpChanges = false,
opChangesType = 0,
): Promise<T> {
try {
const inputBytes = input.toBinary();
const path = `/_anki/${method}`;
const outputBytes = await postProtoInner(path, inputBytes, hasOpChanges);
const outputBytes = await postProtoInner(path, inputBytes, opChangesType);
return outputType.fromBinary(outputBytes);
} catch (err) {
const { alertOnError = true } = options;
@ -27,14 +27,10 @@ export async function postProto<T>(
}
}
async function postProtoInner(url: string, body: Uint8Array, hasOpChanges: boolean): Promise<Uint8Array> {
const headers = { "Content-Type": "application/binary" };
if (hasOpChanges) {
headers["Has-Op-Changes"] = "1";
}
async function postProtoInner(url: string, body: Uint8Array, opChangesType: number): Promise<Uint8Array> {
const result = await fetch(url, {
method: "POST",
headers,
headers: { "Content-Type": "application/binary", "Anki-Op-Changes": opChangesType.toString() },
body,
});
if (!result.ok) {