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 7, 2022
1 parent 68d63f4 commit cba2126
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 14 deletions.
4 changes: 4 additions & 0 deletions flutter/realm_flutter/tests/test_driver/realm_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import 'package:test_api/src/backend/invoker.dart';
// ignore: implementation_imports
import 'package:test_api/src/backend/state.dart' as test_api;

import '../test/application_test.dart' as application_test;
import '../test/application_configuration_test.dart' as application_configuration;
import '../test/configuration_test.dart' as configuration_test;
import '../test/realm_test.dart' as realm_tests;
import '../test/realm_object_test.dart' as realm_object_tests;
Expand All @@ -17,6 +19,8 @@ Future<String> main(List<String> args) async {
final Completer<String> completer = Completer<String>();
final List<String> failedTests = [];

await application_test.main(args);
await application_configuration.main(args);
await configuration_test.main(args);
await realm_tests.main(args);
await realm_object_tests.main(args);
Expand Down
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 AppHandle _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 {
AppHandle get handle => _handle;
}
92 changes: 80 additions & 12 deletions lib/src/native/realm_core.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,21 @@
// 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;
import 'dart:io';
import 'dart:typed_data';

// Hide StringUtf8Pointer.toNativeUtf8 and StringUtf16Pointer since these allows silently allocating memory. Use toUtf8Ptr instead
import 'package:ffi/ffi.dart' hide StringUtf8Pointer, StringUtf16Pointer;
import 'package:pub_semver/pub_semver.dart';

import '../application.dart';
import '../application_configuration.dart';
import '../collections.dart';
import '../configuration.dart';
import '../credentials.dart';
import '../init.dart';
import '../list.dart';
import '../realm_class.dart';
Expand Down Expand Up @@ -67,11 +69,16 @@ enum _CustomErrorCode {
extension on _CustomErrorCode {
int get code {
switch (this) {
case _CustomErrorCode.noError: return 0;
case _CustomErrorCode.httpClientDisposed: return 997;
case _CustomErrorCode.unknownHttp: return 998;
case _CustomErrorCode.unknown: return 999;
case _CustomErrorCode.timeout: return 1000;
case _CustomErrorCode.noError:
return 0;
case _CustomErrorCode.httpClientDisposed:
return 997;
case _CustomErrorCode.unknownHttp:
return 998;
case _CustomErrorCode.unknown:
return 999;
case _CustomErrorCode.timeout:
return 1000;
}
}
}
Expand Down Expand Up @@ -309,7 +316,7 @@ class _RealmCore {

// Report back to core
responseRef.status_code = response.statusCode;
responseRef.body = responseBody.toInt8Ptr(arena);
responseRef.body = responseBody.toUint8Ptr(arena).cast();
responseRef.body_size = responseBody.length;

int headerCnt = 0;
Expand All @@ -320,12 +327,13 @@ class _RealmCore {
responseRef.headers = arena<realm_http_header>(headerCnt);
responseRef.num_headers = headerCnt;

int idx = 0;
response.headers.forEach((name, values) {
int idx = 0;
for (final value in values) {
final headerRef = responseRef.headers.elementAt(idx).ref;
headerRef.name = name.toUtf8Ptr(arena);
headerRef.value = value.toUtf8Ptr(arena);
idx++;
}
});

Expand Down Expand Up @@ -840,12 +848,58 @@ class _RealmCore {
}
_realmLib.realm_app_config_set_platform(handle._pointer, Platform.operatingSystem.toUtf8Ptr(arena));
_realmLib.realm_app_config_set_platform_version(handle._pointer, Platform.operatingSystemVersion.toUtf8Ptr(arena));
final version = Version.parse(Platform.version);
final version = Version.parse(Platform.version.split(' ')[0]);
_realmLib.realm_app_config_set_sdk_version(handle._pointer, version.toString().toUtf8Ptr(arena));

return handle;
});
}

SyncClientConfigHandle createSyncClientConfig(ApplicationConfiguration configuration) {
return using((arena) {
final c = configuration;
final handle = SyncClientConfigHandle._(_realmLib.realm_sync_client_config_new());
if (c.baseFilePath != null) {
_realmLib.realm_sync_client_config_set_base_file_path(handle._pointer, c.baseFilePath!.path.toUtf8Ptr(arena));
}
_realmLib.realm_sync_client_config_set_metadata_mode(handle._pointer, c.metadataPersistenceMode.index);
if (c.metadataEncryptionKey != null && c.metadataPersistenceMode == MetadataPersistenceMode.encrypted) {
_realmLib.realm_sync_client_config_set_metadata_encryption_key(handle._pointer, c.metadataEncryptionKey!.toUint8Ptr(arena));
}
return handle;
});
}

AppHandle getApp(ApplicationConfiguration configuration) {
final httpTransport = createHttpTransport(configuration.httpClient);
final appConfig = createAppConfig(configuration, httpTransport);
final syncClientConfig = createSyncClientConfig(configuration);
return AppHandle._(_realmLib.invokeGetPointer(() => _realmLib.realm_app_get(appConfig._pointer, syncClientConfig._pointer)));
}

static void _logInCallback(Pointer<Void> userdata, Pointer<realm_user> user, Pointer<realm_app_error> error) {
final userHandleCompleter = _realmLib.gc_handle_deref(userdata);
if (userHandleCompleter is Completer<UserHandle>) {
if (error == nullptr) {
userHandleCompleter.complete(UserHandle._(user));
} else {
final message = error.ref.message.cast<Utf8>().toDartString();
userHandleCompleter.completeError(RealmException(message));
}
}
}

Future<UserHandle> logIn(Application application, Credentials credentials) async {
final completer = Completer<UserHandle>();
_realmLib.realm_app_log_in_with_credentials(
application.handle._pointer,
credentials.handle._pointer,
Pointer.fromFunction(_logInCallback),
_realmLib.gc_handle_weak_new(completer),
nullptr,
);
return completer.future;
}
}

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

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

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

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

extension on List<int> {
Pointer<Int8> toInt8Ptr(Allocator allocator) {
Pointer<Uint8> toUint8Ptr(Allocator allocator) {
final nativeSize = length + 1;
final result = allocator<Uint8>(nativeSize);
final Uint8List native = result.asTypedList(nativeSize);
native.setAll(0, this); // copy
native.last = 0; // zero terminate
return result.cast();
return result;
}
}

extension _StringEx on String {
Pointer<Int8> toUtf8Ptr(Allocator allocator) {
final units = utf8.encode(this);
return units.toInt8Ptr(allocator);
return units.toUint8Ptr(allocator).cast();
}

Pointer<realm_string_t> toRealmString(Allocator allocator) {
Expand Down
6 changes: 4 additions & 2 deletions lib/src/realm_class.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ import 'realm_object.dart';
import 'results.dart';

// always expose with `show` to explicitly control the public API surface
export "application_configuration.dart" show ApplicationConfiguration, MetadataPersistenceMode;
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 'credentials.dart' show Credentials, AuthProvider;
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.
///
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 UserHandle _handle;

User._(this._handle);
}

extension UserInternal on User {
static User create(UserHandle handle) => User._(handle);
}
1 change: 1 addition & 0 deletions src/realm_dart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ void dummy(void) {
realm_app_credentials_new_anonymous();
realm_http_transport_new(nullptr, nullptr, nullptr);
realm_app_config_new(nullptr, nullptr);
realm_sync_client_config_new();
#if (ANDROID)
realm_android_dummy();
#endif
Expand Down
37 changes: 37 additions & 0 deletions test/application_test.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 'dart:io';

import '../lib/realm.dart';
import 'test.dart';

Future<void> main([List<String>? args]) async {
print("Current PID $pid");

setupTests(args);

test('Application can be created', () async {
final configuration = ApplicationConfiguration(
Platform.environment['BAAS_PROJECT_ID'] ?? generateRandomString(10),
baseFilePath: Directory.current,
);
final application = Application(configuration);
final credentials = Credentials.anonymous();
final user = await application.logIn(credentials);
});
}

0 comments on commit cba2126

Please sign in to comment.