working sync complete

This commit is contained in:
Henry Hiles 2026-01-26 19:39:02 +00:00
commit 6afa169af9
No known key found for this signature in database
11 changed files with 61 additions and 100 deletions

View file

@ -25,7 +25,7 @@ Future<void> main(List<String> args) => build(args, (input, output) async {
final gomuksBuildDir = buildDir.resolve("gomuks/"); final gomuksBuildDir = buildDir.resolve("gomuks/");
final libFile = gomuksBuildDir.resolve(libFileName); final libFile = gomuksBuildDir.resolve(libFileName);
print("Building Gomuks shared library $libFileName..."); print("Building Gomuks shared library $libFileName from source...");
final result = await Process.run("go", [ final result = await Process.run("go", [
"build", "build",
"-o", "-o",
@ -48,6 +48,7 @@ Future<void> main(List<String> args) => build(args, (input, output) async {
file: libFile, file: libFile,
), ),
) )
..dependencies.add(libFile); ..dependencies.add(libFile)
..dependencies.add(gomuksBuildDir);
print("Done!"); print("Done!");
}); });

View file

@ -9,7 +9,7 @@ import "package:nexus/controllers/sync_status_controller.dart";
import "package:nexus/helpers/extensions/gomuks_buffer.dart"; import "package:nexus/helpers/extensions/gomuks_buffer.dart";
import "package:nexus/models/client_state.dart"; import "package:nexus/models/client_state.dart";
import "package:nexus/models/login.dart"; import "package:nexus/models/login.dart";
import "package:nexus/models/sync_complete.dart"; import "package:nexus/models/sync_data.dart";
import "package:nexus/models/sync_status.dart"; import "package:nexus/models/sync_status.dart";
import "package:nexus/src/third_party/gomuks.g.dart"; import "package:nexus/src/third_party/gomuks.g.dart";
import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:flutter_riverpod/flutter_riverpod.dart";
@ -20,17 +20,18 @@ class ClientController extends AsyncNotifier<int> {
final handle = await Isolate.run(GomuksInit); final handle = await Isolate.run(GomuksInit);
ref.onDispose(() => GomuksDestroy(handle)); ref.onDispose(() => GomuksDestroy(handle));
GomuksStart( final errorCode = GomuksStart(
handle, handle,
NativeCallable< NativeCallable<
Void Function(Pointer<Char>, Int64, GomuksBorrowedBuffer) Void Function(Pointer<Char>, Int64, GomuksOwnedBuffer)
>.listener(( >.listener((
Pointer<Char> command, Pointer<Char> command,
int requestId, int requestId,
GomuksBorrowedBuffer data, GomuksOwnedBuffer data,
) { ) {
try { try {
final muksEventType = command.cast<Utf8>().toDartString(); final muksEventType = command.cast<Utf8>().toDartString();
debugPrint("Handling $muksEventType...");
final Map<String, dynamic> decodedMuksEvent = data.toJson(); final Map<String, dynamic> decodedMuksEvent = data.toJson();
switch (muksEventType) { switch (muksEventType) {
@ -45,9 +46,9 @@ class ClientController extends AsyncNotifier<int> {
.set(SyncStatus.fromJson(decodedMuksEvent)); .set(SyncStatus.fromJson(decodedMuksEvent));
break; break;
case "sync_complete": case "sync_complete":
debugger(message: jsonEncode(decodedMuksEvent)); final syncData = SyncData.fromJson(decodedMuksEvent);
final thing = SyncComplete.fromJson(decodedMuksEvent); debugPrint(jsonEncode(syncData.toJson()));
debugger(message: jsonEncode(thing.toJson()));
// ref // ref
// .watch(SyncStatusController.provider.notifier) // .watch(SyncStatusController.provider.notifier)
// .set(SyncStatus.fromJson(decodedMuksEvent)); // .set(SyncStatus.fromJson(decodedMuksEvent));
@ -58,14 +59,17 @@ class ClientController extends AsyncNotifier<int> {
default: default:
debugPrint("Unhandled event: $muksEventType"); debugPrint("Unhandled event: $muksEventType");
} }
debugPrint("Finished handling $muksEventType...");
} catch (error, stackTrace) { } catch (error, stackTrace) {
debugger();
debugPrintStack(stackTrace: stackTrace, label: error.toString()); debugPrintStack(stackTrace: stackTrace, label: error.toString());
} }
}) })
.nativeFunction, .nativeFunction,
); );
return handle; if (errorCode == 0) return handle;
throw Exception("GomuksStart returned error code $errorCode");
} }
Future<Map<String, dynamic>> sendCommand( Future<Map<String, dynamic>> sendCommand(

View file

@ -1,13 +0,0 @@
import "package:matrix/matrix.dart";
import "package:nexus/models/full_room.dart";
extension GetFullRoom on Room {
Future<FullRoom> get fullRoom async {
await loadHeroUsers();
return FullRoom(
roomData: this,
title: getLocalizedDisplayname(),
avatar: await avatar?.getThumbnailUri(client, width: 24, height: 24),
);
}
}

View file

@ -1,23 +1,9 @@
import "dart:convert"; import "dart:convert";
import "dart:ffi"; import "dart:ffi";
import "dart:typed_data"; import "dart:typed_data";
import "package:ffi/ffi.dart"; import "package:ffi/ffi.dart";
import "package:nexus/src/third_party/gomuks.g.dart"; import "package:nexus/src/third_party/gomuks.g.dart";
extension GomuksBorrowedBufferToJson on GomuksBorrowedBuffer {
Uint8List toBytes() {
if (base == nullptr || length <= 0) return Uint8List(0);
return base.asTypedList(length);
}
Map<String, dynamic> toJson() {
final bytes = toBytes();
if (bytes.isEmpty) return {};
return jsonDecode(utf8.decode(bytes));
}
}
extension GomuksOwnedBufferToJson on GomuksOwnedBuffer { extension GomuksOwnedBufferToJson on GomuksOwnedBuffer {
Uint8List toBytes() { Uint8List toBytes() {
try { try {

View file

@ -1,14 +0,0 @@
import "package:freezed_annotation/freezed_annotation.dart";
part "content_uri.freezed.dart";
part "content_uri.g.dart";
@freezed
abstract class ContentUri with _$ContentUri {
const factory ContentUri({
required String homeserver,
required String fileID,
}) = _ContentUri;
factory ContentUri.fromJson(Map<String, Object?> json) =>
_$ContentUriFromJson(json);
}

View file

@ -9,24 +9,24 @@ abstract class Event with _$Event {
@JsonKey(name: "rowid") required int rowId, @JsonKey(name: "rowid") required int rowId,
@JsonKey(name: "timeline_rowid") required int timelineRowId, @JsonKey(name: "timeline_rowid") required int timelineRowId,
required String roomId, required String roomId,
required int eventId, required String eventId,
@JsonKey(name: "sender") required int authorId, @JsonKey(name: "sender") required String authorId,
required String type, required String type,
required String stateKey, String? stateKey,
@EpochDateTimeConverter() required DateTime timestamp, @EpochDateTimeConverter() required DateTime timestamp,
required Map<String, dynamic> content, required Map<String, dynamic> content,
required Map<String, dynamic> decrypted, Map<String, dynamic>? decrypted,
required Map<String, dynamic> decryptedType, String? decryptedType,
required Map<String, dynamic> unsigned, @Default({}) Map<String, dynamic> unsigned,
required LocalContent localContent, LocalContent? localContent,
required String transactionId, String? transactionId,
required String redactedBy, String? redactedBy,
required String relatesTo, String? relatesTo,
required String relatesType, String? relatesType,
required String decryptionError, String? decryptionError,
required String sendError, String? sendError,
required Map<String, int> reactions, @Default({}) Map<String, int> reactions,
required int lastEditRowId, int? lastEditRowId,
@UnreadTypeConverter() UnreadType? unreadType, @UnreadTypeConverter() UnreadType? unreadType,
}) = _Event; }) = _Event;
@ -36,13 +36,11 @@ abstract class Event with _$Event {
@freezed @freezed
abstract class LocalContent with _$LocalContent { abstract class LocalContent with _$LocalContent {
const factory LocalContent({ const factory LocalContent({
required String sanitizedHtml, String? sanitizedHtml,
required String htmlVersion, bool? wasPlaintext,
required bool wasPlaintext, bool? bigEmoji,
required bool bigEmoji, bool? hasMath,
required bool hasMath, bool? replyFallbackRemoved,
required String editSource,
required String replyFallbackRemoved,
}) = _LocalContent; }) = _LocalContent;
factory LocalContent.fromJson(Map<String, Object?> json) => factory LocalContent.fromJson(Map<String, Object?> json) =>

View file

@ -5,7 +5,7 @@ part "lazy_load_summary.g.dart";
@freezed @freezed
abstract class LazyLoadSummary with _$LazyLoadSummary { abstract class LazyLoadSummary with _$LazyLoadSummary {
const factory LazyLoadSummary({ const factory LazyLoadSummary({
required List<String> heroes, required List<String>? heroes,
required int? joinedMemberCount, required int? joinedMemberCount,
required int? invitedMemberCount, required int? invitedMemberCount,
}) = _LazyLoadSummary; }) = _LazyLoadSummary;

View file

@ -9,12 +9,12 @@ part "room.g.dart";
abstract class Room with _$Room { abstract class Room with _$Room {
const factory Room({ const factory Room({
@JsonKey(name: "meta") RoomMetadata? metadata, @JsonKey(name: "meta") RoomMetadata? metadata,
required List<TimelineRowTuple> timeline, @Default([]) List<TimelineRowTuple> timeline,
required bool reset, required bool reset,
required Map<String, Map> state, required Map<String, Map> state,
// required Map<String, AccountData> accountData, // required Map<String, AccountData> accountData,
required List<Event> events, required List<Event> events,
required Map<String, List<ReadReceipt>> receipts, @Default({}) Map<String, List<ReadReceipt>> receipts,
required bool dismissNotifications, required bool dismissNotifications,
// required List<Notification> notifications, // required List<Notification> notifications,
}) = _Room; }) = _Room;
@ -26,7 +26,7 @@ abstract class Room with _$Room {
abstract class TimelineRowTuple with _$TimelineRowTuple { abstract class TimelineRowTuple with _$TimelineRowTuple {
const factory TimelineRowTuple({ const factory TimelineRowTuple({
@JsonKey(name: "timeline_rowid") required int timelineRowId, @JsonKey(name: "timeline_rowid") required int timelineRowId,
@JsonKey(name: "timeline_eventid") required int eventRowId, @JsonKey(name: "timeline_eventid") int? eventRowId,
}) = _TimelineRowTuple; }) = _TimelineRowTuple;
factory TimelineRowTuple.fromJson(Map<String, Object?> json) => factory TimelineRowTuple.fromJson(Map<String, Object?> json) =>

View file

@ -1,5 +1,4 @@
import "package:freezed_annotation/freezed_annotation.dart"; import "package:freezed_annotation/freezed_annotation.dart";
import "package:nexus/models/content_uri.dart";
import "package:nexus/models/epoch_date_time_converter.dart"; import "package:nexus/models/epoch_date_time_converter.dart";
import "package:nexus/models/lazy_load_summary.dart"; import "package:nexus/models/lazy_load_summary.dart";
part "room_metadata.freezed.dart"; part "room_metadata.freezed.dart";
@ -12,12 +11,12 @@ abstract class RoomMetadata with _$RoomMetadata {
// required CreateEventContent creationContent, // required CreateEventContent creationContent,
// required TombstoneEventContent tombstoneEventContent, // required TombstoneEventContent tombstoneEventContent,
String? name, String? name,
ContentUri? avatar, Uri? avatar,
String? topic, String? topic,
String? canonicalAlias, String? canonicalAlias,
LazyLoadSummary? lazyLoadSummary, LazyLoadSummary? lazyLoadSummary,
required bool hasMemberList, required bool hasMemberList,
@JsonKey(name: "preview_event_rowid") required String previewEventRowID, @JsonKey(name: "preview_event_rowid") required int previewEventRowID,
@EpochDateTimeConverter() required DateTime sortingTimestamp, @EpochDateTimeConverter() required DateTime sortingTimestamp,
@Default(false) bool markedUnread, @Default(false) bool markedUnread,
}) = _RoomMetadata; }) = _RoomMetadata;

View file

@ -1,20 +0,0 @@
import "package:freezed_annotation/freezed_annotation.dart";
import "package:nexus/models/room.dart";
part "sync_complete.freezed.dart";
part "sync_complete.g.dart";
@freezed
abstract class SyncComplete with _$SyncComplete {
const factory SyncComplete({
@Default(false) bool clearState,
// required Map<String, AccountData> accountData,
required Map<String, Room> rooms,
required List<String> leftRooms,
// required List<InvitedRoom> invitedRooms,
// required List<SpaceEdge> spaceEdges,
required List<String> topLevelSpaces,
}) = _SyncComplete;
factory SyncComplete.fromJson(Map<String, Object?> json) =>
_$SyncCompleteFromJson(json);
}

20
lib/models/sync_data.dart Normal file
View file

@ -0,0 +1,20 @@
import "package:freezed_annotation/freezed_annotation.dart";
import "package:nexus/models/room.dart";
part "sync_data.freezed.dart";
part "sync_data.g.dart";
@freezed
abstract class SyncData with _$SyncData {
const factory SyncData({
@Default(false) bool clearState,
// required Map<String, AccountData> accountData,
@Default({}) Map<String, Room> rooms,
@Default([]) List<String> leftRooms,
// required List<InvitedRoom> invitedRooms,
// required List<SpaceEdge> spaceEdges,
@Default([]) List<String> topLevelSpaces,
}) = _SyncData;
factory SyncData.fromJson(Map<String, Object?> json) =>
_$SyncDataFromJson(json);
}