diff --git a/ffigen/config.yaml b/ffigen/config.yaml index bd87bab7f..2fcf317f6 100644 --- a/ffigen/config.yaml +++ b/ffigen/config.yaml @@ -5,6 +5,7 @@ headers: entry-points: - 'realm.h' - 'realm_dart.h' + - 'realm_dart_app.h' - 'realm_dart_scheduler.h' - 'realm_dart_collections.h' - 'realm_dart_http_transport.h' @@ -12,6 +13,7 @@ headers: include-directives: #generate only for these headers - 'realm.h' - 'realm_dart.h' + - 'realm_dart_app.h' - 'realm_dart_scheduler.h' - 'realm_dart_collections.h' - 'realm_dart_http_transport.h' diff --git a/ffigen/realm_dart_app.h b/ffigen/realm_dart_app.h new file mode 120000 index 000000000..6f5c0c684 --- /dev/null +++ b/ffigen/realm_dart_app.h @@ -0,0 +1 @@ +../src/realm_dart_app.h \ No newline at end of file diff --git a/lib/src/application.dart b/lib/src/application.dart new file mode 100644 index 000000000..8e49918e8 --- /dev/null +++ b/lib/src/application.dart @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// +import 'application_configuration.dart'; + +import 'native/realm_core.dart'; +import 'credentials.dart'; +import 'user.dart'; + +class Application { + final RealmAppHandle _handle; + + Application(ApplicationConfiguration configuration) : _handle = realmCore.getApp(configuration.handle); + + Future logIn(Credentials credentials) async { + return UserInternal.create(await realmCore.logIn(_handle, credentials.handle)); + } +} diff --git a/lib/src/application_configuration.dart b/lib/src/application_configuration.dart index d8cda526c..aa83657e6 100644 --- a/lib/src/application_configuration.dart +++ b/lib/src/application_configuration.dart @@ -49,3 +49,7 @@ class ApplicationConfiguration { realmCore.setAppConfigSdkVersion(_handle, Version.parse(Platform.version.takeUntil(' '))); } } + +extension ApplicationConfigurationInternal on ApplicationConfiguration { + RealmAppConfigHandle get handle => _handle; +} \ No newline at end of file diff --git a/lib/src/credentials.dart b/lib/src/credentials.dart new file mode 100644 index 000000000..c4685cc2c --- /dev/null +++ b/lib/src/credentials.dart @@ -0,0 +1,32 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +// Stubs for Credentials + +import 'native/realm_core.dart'; + +class Credentials { + late final RealmAppCredentialsHandle _handle; + + Credentials.anonymous(); +} + +extension CredentialsInternal on Credentials{ + RealmAppCredentialsHandle get handle => _handle; +} + diff --git a/lib/src/native/realm_bindings.dart b/lib/src/native/realm_bindings.dart index e1cf9c64b..8ea22423a 100644 --- a/lib/src/native/realm_bindings.dart +++ b/lib/src/native/realm_bindings.dart @@ -3,7 +3,6 @@ // Generated by `package:ffigen`. import 'dart:ffi' as ffi; -/// A MacOs config for ffigen Usage: dart run ffigen --config macos.yaml class RealmLibrary { /// Holds the symbol lookup function. final ffi.Pointer Function(String symbolName) @@ -7450,6 +7449,41 @@ class RealmLibrary { late final _realm_delete_finalizable = _realm_delete_finalizablePtr .asFunction(); + /// @brief + /// + /// @param completion + /// @param userdata + /// @return true if operation started successfully, false if an error occurred. + bool realm_dart_app_log_in_with_credentials( + ffi.Pointer arg0, + ffi.Pointer arg1, + realm_dart_app_user_completion_func_t completion, + Object userdata, + ) { + return _realm_dart_app_log_in_with_credentials( + arg0, + arg1, + completion, + userdata, + ) != + 0; + } + + late final _realm_dart_app_log_in_with_credentialsPtr = _lookup< + ffi.NativeFunction< + ffi.Uint8 Function( + ffi.Pointer, + ffi.Pointer, + realm_dart_app_user_completion_func_t, + ffi.Handle)>>('realm_dart_app_log_in_with_credentials'); + late final _realm_dart_app_log_in_with_credentials = + _realm_dart_app_log_in_with_credentialsPtr.asFunction< + int Function( + ffi.Pointer, + ffi.Pointer, + realm_dart_app_user_completion_func_t, + Object)>(); + ffi.Pointer realm_dart_create_scheduler( int isolateId, int port, @@ -8574,6 +8608,20 @@ typedef Dart_FinalizableHandle = ffi.Pointer<_Dart_FinalizableHandle>; class _Dart_FinalizableHandle extends ffi.Opaque {} +/// Completion callback for asynchronous Realm App operations that yield a user object. +/// +/// @param userdata The userdata the asynchronous operation was started with. +/// @param user User object produced by the operation, or null if it failed. +/// The pointer is alive only for the duration of the callback, +/// if you wish to use it further make a copy with realm_clone(). +/// @param error Pointer to an error object if the operation failed, otherwise null if it completed successfully. +/// +/// This is a dart specific version of the completion callback for asynchronous Realm operations. +typedef realm_dart_app_user_completion_func_t = ffi.Pointer< + ffi.NativeFunction< + ffi.Void Function(ffi.Handle, ffi.Pointer, + ffi.Pointer)>>; + /// A port is used to send or receive inter-isolate messages typedef Dart_Port = ffi.Int64; typedef realm_dart_on_collection_change_func_t = ffi.Pointer< diff --git a/lib/src/native/realm_core.dart b/lib/src/native/realm_core.dart index 86c445c23..45666c87d 100644 --- a/lib/src/native/realm_core.dart +++ b/lib/src/native/realm_core.dart @@ -18,6 +18,7 @@ // ignore_for_file: constant_identifier_names, non_constant_identifier_names +import 'dart:async'; import 'dart:convert'; import 'dart:ffi'; import 'dart:ffi' as ffi show Handle; @@ -801,6 +802,32 @@ class _RealmCore { _realmLib.realm_app_config_set_sdk_version(handle._pointer, versionString.toUtf8Ptr(arena)); }); } + + RealmAppHandle getApp(RealmAppConfigHandle appConfig) { + return RealmAppHandle._(_realmLib.realm_app_get(appConfig._pointer, nullptr)); // TODO: realm_sync_client_config + } + + static void _loginCallback(Object userdata, Pointer user, Pointer error) { + if (userdata is Completer) { + if (error != nullptr) { + final message = error.ref.message.cast().toDartString(); + userdata.completeError(RealmException(message)); + } else { + userdata.complete(RealmUserHandle._(_realmLib.realm_clone(user.cast()).cast())); + } + } + } + + Future logIn(RealmAppHandle app, RealmAppCredentialsHandle credentials) { + final completer = Completer(); + _realmLib.invokeGetBool(() => _realmLib.realm_dart_app_log_in_with_credentials( + app._pointer, + credentials._pointer, + Pointer.fromFunction(_loginCallback), + completer, + )); + return completer.future; + } } class LastError { @@ -901,6 +928,18 @@ class RealmAppConfigHandle extends Handle { RealmAppConfigHandle._(Pointer pointer) : super(pointer, 256); // TODO: What should hint be? } +class RealmAppHandle extends Handle { + RealmAppHandle._(Pointer pointer) : super(pointer, 256); // TODO: What should hint be? +} + +class RealmAppCredentialsHandle extends Handle { + RealmAppCredentialsHandle._(Pointer pointer) : super(pointer, 256); // TODO: What should hint be? +} + +class RealmUserHandle extends Handle { + RealmUserHandle._(Pointer pointer) : super(pointer, 256); // TODO: What should hint be? +} + extension on List { Pointer toInt8Ptr(Allocator allocator) { final nativeSize = length + 1; diff --git a/lib/src/realm_class.dart b/lib/src/realm_class.dart index c287ca4a1..1e4dfe96f 100644 --- a/lib/src/realm_class.dart +++ b/lib/src/realm_class.dart @@ -32,11 +32,15 @@ import 'results.dart'; // always expose with `show` to explicitly control the public API surface export 'package:realm_common/realm_common.dart' show Ignored, Indexed, MapTo, PrimaryKey, RealmError, RealmModel, RealmUnsupportedSetError, RealmStateError, RealmCollectionType, RealmPropertyType; + +export 'application.dart' show Application; +export 'application_configuration.dart' show ApplicationConfiguration; export "configuration.dart" show Configuration, RealmSchema, SchemaObject; export 'list.dart' show RealmList, RealmListOfObject, RealmListChanges; export 'realm_object.dart' show RealmEntity, RealmException, RealmObject, RealmObjectChanges; export 'realm_property.dart'; export 'results.dart' show RealmResults, RealmResultsChanges; +export 'user.dart' show User; /// A [Realm] instance represents a `Realm` database. /// diff --git a/lib/src/user.dart b/lib/src/user.dart new file mode 100644 index 000000000..e92a605b8 --- /dev/null +++ b/lib/src/user.dart @@ -0,0 +1,29 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +import 'native/realm_core.dart'; + +class User { + final RealmUserHandle _handle; + + User._(this._handle); +} + +extension UserInternal on User { + static User create(RealmUserHandle handle) => User._(handle); +} \ No newline at end of file diff --git a/src/realm_dart_app.h b/src/realm_dart_app.h new file mode 100644 index 000000000..bf90f828b --- /dev/null +++ b/src/realm_dart_app.h @@ -0,0 +1,48 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef REALM_DART_APP_H +#define REALM_DART_APP_H + +#include "realm.h" +#include "dart_api_dl.h" + +/** + * Completion callback for asynchronous Realm App operations that yield a user object. + * + * @param userdata The userdata the asynchronous operation was started with. + * @param user User object produced by the operation, or null if it failed. + * The pointer is alive only for the duration of the callback, + * if you wish to use it further make a copy with realm_clone(). + * @param error Pointer to an error object if the operation failed, otherwise null if it completed successfully. + * + * This is a dart specific version of the completion callback for asynchronous Realm operations. + */ +typedef void (*realm_dart_app_user_completion_func_t)(Dart_Handle userdata, realm_user_t* user, const realm_app_error_t* error); + +/** + * @brief + * + * @param completion + * @param userdata + * @return true if operation started successfully, false if an error occurred. + */ +RLM_API bool realm_dart_app_log_in_with_credentials(realm_app_t*, realm_app_credentials_t*, + realm_dart_app_user_completion_func_t completion, Dart_Handle userdata); + +#endif \ No newline at end of file