Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use better default path on Flutter #665

Merged
merged 19 commits into from
Jun 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ flutter/realm_flutter/.gradle/
# Ignore native binaries build directories
/build-native/
/build/
/build-linux/
/build-macos/
/build-windows/

# Ignore example pubspec.lock since the example always reference the local package
example/pubspec.lock
Expand Down
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
"xlocmon": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xutility": "cpp"
"xutility": "cpp",
"iosfwd": "cpp",
"sstream": "cpp"
nielsenko marked this conversation as resolved.
Show resolved Hide resolved
},
}
3 changes: 3 additions & 0 deletions flutter/realm_flutter/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ set(realm_bundled_libraries
# message ("PROJECT_SOURCE_DIR is ${PROJECT_SOURCE_DIR}")
# message ("CMAKE_CURRENT_SOURCE_DIR is ${CMAKE_CURRENT_SOURCE_DIR}")

add_definitions(-DAPP_DIR_NAME="${APPLICATION_ID}")


# This works cause realm plugin is always accessed through the .plugin_symlinks directory.
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../ephemeral")
include(${EPHEMERAL_DIR}/generated_config.cmake)
Expand Down
2 changes: 2 additions & 0 deletions flutter/realm_flutter/linux/include/realm/realm_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ FLUTTER_PLUGIN_EXPORT GType realm_plugin_get_type();
FLUTTER_PLUGIN_EXPORT void realm_plugin_register_with_registrar(
FlPluginRegistrar* registrar);

FLUTTER_PLUGIN_EXPORT const char* realm_dart_get_app_directory();

G_END_DECLS

#endif // FLUTTER_PLUGIN_REALM_PLUGIN_H_
12 changes: 12 additions & 0 deletions flutter/realm_flutter/linux/realm_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@

#include <cstring>

#include <string>

#ifndef APP_DIR_NAME
#define APP_DIR_NAME "realm_app"
#endif

#define REALM_PLUGIN(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), realm_plugin_get_type(), \
RealmPlugin))
Expand Down Expand Up @@ -58,3 +64,9 @@ void realm_plugin_register_with_registrar(FlPluginRegistrar* registrar) {

g_object_unref(plugin);
}

static std::string appDirName = APP_DIR_NAME;

const char* realm_dart_get_app_directory() {
return appDirName.c_str();
}
32 changes: 32 additions & 0 deletions flutter/realm_flutter/macos/Classes/platform.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <string>
#include <sstream>
#import <Foundation/Foundation.h>

#import "realm_plugin.h"

static std::string filesDir;

std::string default_realm_file_directory()
{
std::string ret;
std::string bundle;
@autoreleasepool {
NSString *path = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)[0];
ret = path.UTF8String;
return ret;
}
}

// Returns the app directory on the current machine or null if getting the default directory fails
// On macOS this is the /Users/username/Library/Containers/app_name/Data/Library/Application Support
RLM_API const char* realm_dart_get_app_directory() {
if (!filesDir.empty()) {
return filesDir.c_str();
}

std::stringstream ss;
ss << default_realm_file_directory();
filesDir = ss.str();

return filesDir.c_str();
}
10 changes: 10 additions & 0 deletions flutter/realm_flutter/macos/Classes/realm_plugin.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef FLUTTER_PLUGIN_REALM_PLUGIN_H_
#define FLUTTER_PLUGIN_REALM_PLUGIN_H_

#ifdef __cplusplus
#define RLM_API extern "C" __attribute__((visibility("default")))
#else
#define RLM_API
#endif // __cplusplus

#endif // FLUTTER_PLUGIN_REALM_PLUGIN_H_
16 changes: 16 additions & 0 deletions flutter/realm_flutter/windows/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,22 @@ set(realm_bundled_libraries
# For example the tests app refers to the realm plugin using this path .../realm-dart/flutter/realm_flutter/tests/windows/flutter/ephemeral/.plugin_symlinks/realm/windows
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../ephemeral")
include(${EPHEMERAL_DIR}/generated_config.cmake)
set(APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../..")
# message ("APP_DIR is ${APP_DIR}")
set(APP_PUBSPEC_FILE "${APP_DIR}/pubspec.yaml")
# message ("APP_PUBSPEC_FILE is ${APP_PUBSPEC_FILE}")

file(READ "${APP_PUBSPEC_FILE}" PUBSPEC_CONTENT)
# name:\\s*([a-z0-9_]+)
# message ("${PUBSPEC_CONTENT}")
string(REGEX MATCH "name:[ \r\n\t]*([a-z0-9_]*)" _ ${PUBSPEC_CONTENT})
# message ("Pubspec name 0 is ${CMAKE_MATCH_0}")
# message ("Package name is ${CMAKE_MATCH_1}")
set(APP_DIR_NAME ${CMAKE_MATCH_1})

#message ("BINARY_NAME is ${BINARY_NAME}")
add_definitions(-DAPP_DIR_NAME="${APP_DIR_NAME}")


# message ("FLUTTER_TOOL_ENVIRONMENT is ${FLUTTER_TOOL_ENVIRONMENT}")
# message ("FLUTTER_ROOT is ${FLUTTER_ROOT}")
Expand Down
2 changes: 2 additions & 0 deletions flutter/realm_flutter/windows/include/realm/realm_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ extern "C" {
FLUTTER_PLUGIN_EXPORT void RealmPluginRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar);

FLUTTER_PLUGIN_EXPORT const wchar_t* realm_dart_get_app_directory();

#if defined(__cplusplus)
} // extern "C"
#endif
Expand Down
82 changes: 59 additions & 23 deletions flutter/realm_flutter/windows/realm_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
// This must be included before many other Windows headers.
#include <windows.h>

#include <shlobj_core.h>
#include <Knownfolders.h>
#include <combaseapi.h>
#include <sstream>

#include <flutter/method_channel.h>
#include <flutter/plugin_registrar_windows.h>
#include <flutter/standard_method_codec.h>
Expand All @@ -11,56 +16,87 @@
#include <memory>
#include <sstream>

#ifndef APP_DIR_NAME
#define APP_DIR_NAME "realm_app"
#endif

// #pragma message("APP_DIR_NAME is " _CRT_STRINGIZE(APP_DIR_NAME))

namespace
{
class RealmPlugin : public flutter::Plugin
{
public:
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar);
class RealmPlugin : public flutter::Plugin
{
public:
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar);

RealmPlugin();

virtual ~RealmPlugin();

private:
private:
// Called when a method is called on this plugin's channel from Dart.
void HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue> &method_call,
const flutter::MethodCall<flutter::EncodableValue>& method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
};
};

// static
void RealmPlugin::RegisterWithRegistrar(flutter::PluginRegistrarWindows *registrar)
{
// static
void RealmPlugin::RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar)
{
//TODO: these channels seem unneccessary. Remove if not needed
auto channel = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(registrar->messenger(), "realm", &flutter::StandardMethodCodec::GetInstance());

auto plugin = std::make_unique<RealmPlugin>();

channel->SetMethodCallHandler(
[plugin_pointer = plugin.get()](const auto &call, auto result)
{
plugin_pointer->HandleMethodCall(call, std::move(result));
});
[plugin_pointer = plugin.get()](const auto& call, auto result)
{
plugin_pointer->HandleMethodCall(call, std::move(result));
});

registrar->AddPlugin(std::move(plugin));
}
}

RealmPlugin::RealmPlugin() {}
RealmPlugin::RealmPlugin() {}

RealmPlugin::~RealmPlugin() {}
RealmPlugin::~RealmPlugin() {}

void RealmPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue> &method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result)
{
void RealmPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue>& method_call,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result)
{
result->NotImplemented();
}
}

} // namespace

void RealmPluginRegisterWithRegistrar(
FlutterDesktopPluginRegistrarRef registrar)
{
RealmPlugin::RegisterWithRegistrar(flutter::PluginRegistrarManager::GetInstance()->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
RealmPlugin::RegisterWithRegistrar(flutter::PluginRegistrarManager::GetInstance()->GetRegistrar<flutter::PluginRegistrarWindows>(registrar));
}

static std::wstring appDirName;

// Returns the app directory on the current machine or null if getting the default directory fails
// On Windows this is the C:\Users\username\AppData\Roaming\app_name directory
const wchar_t* realm_dart_get_app_directory() {
if (!appDirName.empty()) {
return appDirName.c_str();
}

PWSTR ppszPath;
int hResult = SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DEFAULT, NULL, &ppszPath);
if (!SUCCEEDED(hResult)) {
CoTaskMemFree(ppszPath);
return nullptr;
}

std::wstringstream ss;
ss << ppszPath << "\\" << APP_DIR_NAME;
appDirName = ss.str();

CoTaskMemFree(ppszPath);

return appDirName.c_str();
}
11 changes: 8 additions & 3 deletions lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@
import 'dart:io';

import 'package:meta/meta.dart';
import 'package:path/path.dart' as _path;
nielsenko marked this conversation as resolved.
Show resolved Hide resolved

import '../realm.dart';
import 'configuration.dart';
import 'credentials.dart';
import 'native/realm_core.dart';
import 'user.dart';
Expand Down Expand Up @@ -98,7 +98,7 @@ class AppConfiguration {
this.maxConnectionTimeout = const Duration(minutes: 2),
HttpClient? httpClient,
}) : baseUrl = baseUrl ?? Uri.parse('https://realm.mongodb.com'),
baseFilePath = baseFilePath ?? Directory(ConfigurationInternal.defaultStorageFolder),
baseFilePath = baseFilePath ?? Directory(_path.dirname(Configuration.defaultRealmPath)),
httpClient = httpClient ?? HttpClient();
}

Expand All @@ -116,10 +116,15 @@ class App {
String get id => realmCore.appGetId(this);

/// Create an app with a particular [AppConfiguration]
App(AppConfiguration configuration) : this._(realmCore.getApp(configuration));
App(AppConfiguration configuration) : this._(_getApp(configuration));

App._(this._handle);

static AppHandle _getApp(AppConfiguration configuration) {
configuration.baseFilePath.createSync(recursive: true);
return realmCore.getApp(configuration);
}

/// Logs in a user with the given credentials.
Future<User> logIn(Credentials credentials) async {
var userHandle = await realmCore.logIn(this, credentials);
Expand Down
44 changes: 25 additions & 19 deletions lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import 'package:path/path.dart' as _path;

import 'native/realm_core.dart';
import 'realm_class.dart';
import 'init.dart';

/// The signature of a callback used to determine if compaction
/// should be attempted.
Expand All @@ -47,29 +48,43 @@ typedef InitialDataCallback = void Function(Realm realm);
/// Configuration used to create a [Realm] instance
/// {@category Configuration}
abstract class Configuration {
static const String _defaultRealmName = 'default.realm';

static String get _defaultStorageFolder {
if (Platform.isAndroid || Platform.isIOS) {
return realmCore.getFilesPath();
/// The default realm filename to be used.
static String get defaultRealmName => _path.basename(defaultRealmPath);
static set defaultRealmName(String name) => defaultRealmPath = _path.join(_path.dirname(defaultRealmPath), _path.basename(name));


/// The platform dependent path used to store realm files
///
/// On Flutter Android and iOS this is the application's data directory.
/// On Flutter Windows this is the `C:\Users\username\AppData\Roaming\app_name` directory.
/// On Flutter macOS this is the `/Users/username/Library/Containers/app_name/Data/Library/Application Support` directory.
/// On Flutter Linux this is the `/home/username/.local/share/app_name` directory.
/// On Dart standalone Windows, macOS and Linux this is the current directory.
static String get defaultStoragePath {
nielsenko marked this conversation as resolved.
Show resolved Hide resolved
if (isFlutterPlatform) {
return realmCore.getAppDirectory();
}

return Directory.current.path;
}

static String? _defaultPath;
/// The platform dependent path to the default realm file.
///
/// If set it should contain the path and the name of the realm file. Ex. "~/mypath/myrealm.realm"
/// [defaultStoragePath] can be used to build this path.
static late String defaultRealmPath = _path.join(defaultStoragePath, 'default.realm');

Configuration._(
List<SchemaObject> schemaObjects, {
String? path,
this.fifoFilesFallbackPath,
}) : schema = RealmSchema(schemaObjects) {
this.path = _getPath(path);
this.path = path ?? _path.join(_path.dirname(_defaultPath), _path.basename(defaultRealmName));
}

String _getPath(String? path) {
return path ?? _defaultPath ?? _path.join(_defaultStorageFolder, _defaultRealmName);
}
// allow inheritors to override the _defaultPath value
String get _defaultPath => Configuration.defaultRealmPath;

/// Specifies the FIFO special files fallback location.
///
Expand Down Expand Up @@ -161,13 +176,6 @@ abstract class Configuration {
);
}

extension ConfigurationInternal on Configuration {
static String? get defaultPath => Configuration._defaultPath;
static set defaultPath(String? value) => Configuration._defaultPath = value;

static String get defaultStorageFolder => Configuration._defaultStorageFolder;
}

/// [LocalConfiguration] is used to open local [Realm] instances,
/// that are persisted across runs.
/// {@category Configuration}
Expand Down Expand Up @@ -268,9 +276,7 @@ class FlexibleSyncConfiguration extends Configuration {
}) : super._();

@override
String _getPath(String? path) {
return path ?? realmCore.getPathForConfig(this);
}
String get _defaultPath => realmCore.getPathForConfig(this);
}

extension FlexibleSyncConfigurationInternal on FlexibleSyncConfiguration {
Expand Down
Loading