Skip to content

Commit

Permalink
Added Application class with async logIn method (includes stubs for U…
Browse files Browse the repository at this point in the history
…ser)
  • Loading branch information
nielsenko committed Apr 1, 2022
1 parent 89087ec commit a82c789
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 7 deletions.
2 changes: 2 additions & 0 deletions ffigen/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ 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'
- 'realm_android_platform.h'
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'
Expand Down
1 change: 1 addition & 0 deletions ffigen/realm_dart_app.h
37 changes: 37 additions & 0 deletions lib/src/application.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
////////////////////////////////////////////////////////////////////////////////
//
// 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;
final ApplicationConfiguration configuration;

Application(this.configuration) : _handle = realmCore.getApp(configuration);

Future<User> logIn(Credentials credentials) async {
return UserInternal.create(await realmCore.logIn(this, credentials));
}
}

extension ApplicationInternal on Application {
RealmAppHandle get handle => _handle;
}
2 changes: 1 addition & 1 deletion lib/src/application_configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ class ApplicationConfiguration {
this.localAppName,
this.localAppVersion,
});
}
}
50 changes: 49 additions & 1 deletion lib/src/native/realm_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> Function<T extends ffi.NativeType>(String symbolName)
Expand Down Expand Up @@ -7450,6 +7449,41 @@ class RealmLibrary {
late final _realm_delete_finalizable = _realm_delete_finalizablePtr
.asFunction<void Function(Dart_FinalizableHandle, Object)>();

/// @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<realm_app_t> arg0,
ffi.Pointer<realm_app_credentials_t> 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<realm_app_t>,
ffi.Pointer<realm_app_credentials_t>,
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<realm_app_t>,
ffi.Pointer<realm_app_credentials_t>,
realm_dart_app_user_completion_func_t,
Object)>();

ffi.Pointer<realm_scheduler_t> realm_dart_create_scheduler(
int isolateId,
int port,
Expand Down Expand Up @@ -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<realm_user_t>,
ffi.Pointer<realm_app_error_t>)>>;

/// 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<
Expand Down
81 changes: 76 additions & 5 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -28,9 +29,10 @@ import 'dart:typed_data';
import 'package:ffi/ffi.dart' hide StringUtf8Pointer, StringUtf16Pointer;
import 'package:pub_semver/pub_semver.dart';

import '../application_configuration.dart';
import '../application.dart';
import '../collections.dart';
import '../configuration.dart';
import '../credentials.dart';
import '../init.dart';
import '../list.dart';
import '../realm_class.dart';
Expand All @@ -42,6 +44,37 @@ late RealmLibrary _realmLib;

final _RealmCore realmCore = _RealmCore();

enum _CustomErrorCode {
// Awaiting enhanced enums feature in dart 2.17
/*
final int code;
const _CustomErrorCode(this.code);
*/
noError, //(0),
httpClientClosed, //(997),
unknownHttp, //(998),
unknown, //(999),
timeout, //(1000),
}

extension on _CustomErrorCode {
// TODO: Drop once enhanced enums feature lands in dart 2.17
int get code {
switch (this) {
case _CustomErrorCode.noError:
return 0;
case _CustomErrorCode.httpClientClosed:
return 997;
case _CustomErrorCode.unknownHttp:
return 998;
case _CustomErrorCode.unknown:
return 999;
case _CustomErrorCode.timeout:
return 1000;
}
}
}

enum _HttpMethod {
get,
post,
Expand Down Expand Up @@ -238,9 +271,6 @@ class _RealmCore {
await using((arena) async {
final response_pointer = arena<realm_http_response>();
final responseRef = response_pointer.ref;
// pre-fill in case something fails
responseRef.custom_status_code = 100; // TODO!

try {
// Build request
late HttpClientRequest request;
Expand Down Expand Up @@ -294,7 +324,12 @@ class _RealmCore {
}
});

responseRef.custom_status_code = 0; // all is well, reset custom_status_code
responseRef.custom_status_code = _CustomErrorCode.noError.code; // all is well
} on SocketException catch (_) {
// TODO: Timeouts are socket exceptions, but not not all socket exceptions are timeout..
responseRef.custom_status_code = _CustomErrorCode.timeout.code;
} catch (_) {
responseRef.custom_status_code = _CustomErrorCode.unknown.code;
} finally {
_realmLib.realm_http_transport_complete_request(request_context, response_pointer);
}
Expand Down Expand Up @@ -784,6 +819,34 @@ class _RealmCore {
return handle;
});
}

RealmAppHandle getApp(ApplicationConfiguration configuration) {
final httpTransport = realmCore.createHttpTransport(HttpClient());
final appConfig = realmCore.createAppConfig(configuration, httpTransport);
return RealmAppHandle._(_realmLib.realm_app_get(appConfig._pointer, nullptr)); // TODO: realm_sync_client_config
}

static void _loginCallback(Object userdata, Pointer<realm_user> user, Pointer<realm_app_error> error) {
if (userdata is Completer<RealmUserHandle>) {
if (error != nullptr) {
final message = error.ref.message.cast<Utf8>().toDartString();
userdata.completeError(RealmException(message));
} else {
userdata.complete(RealmUserHandle._(_realmLib.realm_clone(user.cast()).cast()));
}
}
}

Future<RealmUserHandle> logIn(Application application, Credentials credentials) {
final completer = Completer<RealmUserHandle>();
_realmLib.invokeGetBool(() => _realmLib.realm_dart_app_log_in_with_credentials(
application.handle._pointer,
credentials.handle._pointer,
Pointer.fromFunction(_loginCallback),
completer,
));
return completer.future;
}
}

class LastError {
Expand Down Expand Up @@ -888,6 +951,14 @@ class AppConfigHandle extends Handle<realm_app_config> {
AppConfigHandle._(Pointer<realm_app_config> pointer) : super(pointer, 256); // TODO: What should hint be?
}

class RealmAppHandle extends Handle<realm_app> {
RealmAppHandle._(Pointer<realm_app> pointer) : super(pointer, 256); // TODO: What should hint be?
}

class RealmUserHandle extends Handle<realm_user> {
RealmUserHandle._(Pointer<realm_user> pointer) : super(pointer, 256); // TODO: What should hint be?
}

extension on List<int> {
Pointer<Int8> toInt8Ptr(Allocator allocator) {
final nativeSize = length + 1;
Expand Down
4 changes: 4 additions & 0 deletions lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@ 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 'credentials.dart' show Credentials, AuthProvider;


/// A [Realm] instance represents a `Realm` database.
///
/// {@category Realm}
Expand Down
29 changes: 29 additions & 0 deletions lib/src/user.dart
Original file line number Diff line number Diff line change
@@ -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);
}
48 changes: 48 additions & 0 deletions src/realm_dart_app.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit a82c789

Please sign in to comment.