Skip to content

Commit

Permalink
windows/linux start
Browse files Browse the repository at this point in the history
  • Loading branch information
dnys1 committed Apr 2, 2024
1 parent f49f6c4 commit 04dd90c
Show file tree
Hide file tree
Showing 12 changed files with 726 additions and 155 deletions.
26 changes: 25 additions & 1 deletion packages/platform/storage/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
# platform_storage

A Dart-only package for accessing platform-native storage functionality.
Provides a unified API for accessing platform-native storage functionality, such as the iOS Keychain and Android SharedPreferences.
Sync and async APIs are provided for all storage operations, where asynchronous APIs use an `Isolate` to perform the operation in
a background thread.

> See [Web support](#Web) below for more info on how this package behaves in a browser environment.
## `PlatformStorage`

All implementations conform to the `PlatformStorage` interface, which provides a simple API for reading and writing key-value pairs.

There are two flavors of `PlatformStorage` currently: `PlatformLocalStorage` and `PlatformSecureStorage`. Both are constructed with
a required `namespace` parameter and optional `scope`. The `namespace` represents the isolation boundary of the storage values, while
the `scope` is used to separate storage data between different parts of the app,

It is recommended to use your application or bundle identifier as the `namespace`.

### `PlatformLocalStorage`

The local storage APIs are useful for storing non-sensitive data that should persist across app restarts and be deleted alongside the app.

The platform implementations for `PlatformLocalStorage` are:
- **iOS/macOS**: The `UserDefaults` API with a [suite name](https://developer.apple.com/documentation/foundation/nsuserdefaults/1409957-initwithsuitename#discussion) of `namespace<.scope>`.
- **Android**: The `SharedPreferences` API with a [name](https://developer.android.com/reference/android/content/Context.html#getSharedPreferences(java.lang.String,%20int)) of `namespace<.scope>`.
- **Linux**: The `gsettings` API with a schema path of `namespace<.scope>`.
- **Windows**: The `Windows.Storage.ApplicationData.Current.LocalSettings` API with a container name of `namespace<.scope>`.
61 changes: 61 additions & 0 deletions packages/platform/storage/lib/src/local/local_storage.linux.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import 'dart:convert';
import 'dart:io';

import 'package:native_synchronization/primitives.dart';
import 'package:path/path.dart' as p;
import 'package:platform_storage/src/local/local_storage_platform.vm.dart';
import 'package:platform_storage/src/native/windows/windows_paths.dart';

final class LocalStoragePlatformLinux extends LocalStoragePlatform {
LocalStoragePlatformLinux({
required super.namespace,
super.scope,
}) : super.base();

final Mutex _mutex = Mutex();
late final String _storagePath = p.joinAll([
// The RoamingAppData folder
PathProviderWindows.getApplicationSupportPath()!,
if (scope != null) '$namespace.$scope.json' else '$namespace.json',
]);
late final File _storage = File(_storagePath);

Map<String, String> _readData() {
if (!_storage.existsSync()) {
return {};
}
return (jsonDecode(_storage.readAsStringSync()) as Map).cast();
}

void _writeData(Map<String, String> data) {
if (!_storage.existsSync()) {
_storage.createSync(recursive: true);
}
_storage.writeAsStringSync(jsonEncode(data));
}

@override
void clear() => _mutex.runLocked(() {
if (_storage.existsSync()) {
_storage.deleteSync();
}
});

@override
String? delete(String key) => _mutex.runLocked(() {
final data = _readData();
final value = data.remove(key);
_writeData(data);
return value;
});

@override
String? read(String key) => _mutex.runLocked(() => _readData()[key]);

@override
String write(String key, String value) => _mutex.runLocked(() {
final data = _readData()..[key] = value;
_writeData(data);
return value;
});
}
69 changes: 30 additions & 39 deletions packages/platform/storage/lib/src/local/local_storage.windows.dart
Original file line number Diff line number Diff line change
@@ -1,59 +1,50 @@
import 'dart:convert';
import 'dart:io';

import 'package:path/path.dart' as p;
import 'package:platform_storage/src/native/windows/windows_paths.dart';
import 'package:platform_storage/src/secure/secure_storage_platform.vm.dart';
import 'package:windows_storage/windows_storage.dart';

final class SecureStoragePlatformWindows extends SecureStoragePlatform {
SecureStoragePlatformWindows({
final class LocalStoragePlatformWindows extends SecureStoragePlatform {
LocalStoragePlatformWindows({
required super.namespace,
super.scope,
}) : super.base();

late final String _storagePath = p.joinAll([
// The RoamingAppData folder
PathProviderWindows.getApplicationSupportPath()!,
if (scope != null) ...[namespace, '$scope.json'] else '$namespace.json',
]);
late final File _storage = File(_storagePath);
final _settings = ApplicationData.current!.roamingSettings!;
late final _container = scope == null
? _settings
: _settings.createContainer(
scope!,
ApplicationDataCreateDisposition.always,
)!;

Map<String, String> _readData() {
if (!_storage.existsSync()) {
return {};
}
return (jsonDecode(_storage.readAsStringSync()) as Map).cast();
}

void _writeData(Map<String, String> data) {
if (!_storage.existsSync()) {
_storage.createSync(recursive: true);
}
_storage.writeAsStringSync(jsonEncode(data));
@override
String? delete(String key) {
final stored = read(key);
_container.values!.remove(key);
return stored;
}

@override
void clear() {
if (_storage.existsSync()) {
_storage.deleteSync();
}
}
String? read(String key) => _container.values!.lookup(key) as String?;

@override
String? delete(String key) {
final data = _readData();
final value = data.remove(key);
_writeData(data);
String write(String key, String value) {
_container.values!.insert(key, value);
return value;
}

@override
String? read(String key) => _readData()[key];
void clear() {
for (final key in _container.values!.getView().keys) {
_container.values!.remove(key);
}
if (scope case final scope?) {
_settings.deleteContainer(scope);
}
}

@override
String write(String key, String value) {
final data = _readData()..[key] = value;
_writeData(data);
return value;
void close() {
_container.close();
_settings.close();
super.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ final class LocalStoragePlatformDarwin extends LocalStoragePlatform {
/// identifier and the scope, which creates a new domain for the user defaults
/// which can be shared between apps.
///
/// See the discussion here: https://developer.apple.com/documentation/foundation/nsuserdefaults/1409957-initwithsuitename?language=objc
/// See the discussion here: https://developer.apple.com/documentation/foundation/nsuserdefaults/1409957-initwithsuitename#discussion
late final _suiteName = () {
final String domain = scope == null ? namespace : '$namespace.$scope';
if (_bundleIdentifier != null && domain == _bundleIdentifier.toString()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'dart:ffi';

import 'package:win32/win32.dart';

/// @nodoc
typedef IUnknown_AddRef_Native = Uint32 Function(VTablePointer lpVtbl);

/// @nodoc
typedef IUnknown_Release_Native = IUnknown_AddRef_Native;

/// @nodoc
typedef IUnknown_QueryInterface_Native = HRESULT Function(
VTablePointer lpVtbl, Pointer<GUID> riid, Pointer<VTablePointer> ppvObject);

/// @nodoc
final class IUnknownVtbl extends Struct {
external Pointer<NativeFunction<IUnknown_QueryInterface_Native>>
QueryInterface;
external Pointer<NativeFunction<IUnknown_AddRef_Native>> AddRef;
external Pointer<NativeFunction<IUnknown_Release_Native>> Release;
}

/// @nodoc
typedef IInspectable_GetIids_Native = HRESULT Function(VTablePointer lpVtbl,
Pointer<Uint32> iidCount, Pointer<Pointer<GUID>> iids);

/// @nodoc
typedef IInspectable_GetRuntimeClassName_Native = HRESULT Function(
VTablePointer lpVtbl, Pointer<IntPtr> className);

/// @nodoc
typedef IInspectable_GetTrustLevel_Native = HRESULT Function(
VTablePointer lpVtbl, Pointer<Int32> trustLevel);

/// @nodoc
final class IInspectableVtbl extends Struct {
external IUnknownVtbl baseVtbl;
external Pointer<NativeFunction<IInspectable_GetIids_Native>> GetIids;
external Pointer<NativeFunction<IInspectable_GetRuntimeClassName_Native>>
GetRuntimeClassName;
external Pointer<NativeFunction<IInspectable_GetTrustLevel_Native>>
GetTrustLevel;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) 2023, Dart | Windows. Please see the AUTHORS file for details.
// All rights reserved. Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// THIS FILE IS GENERATED AUTOMATICALLY AND SHOULD NOT BE EDITED DIRECTLY.

// ignore_for_file: constant_identifier_names, non_constant_identifier_names
// ignore_for_file: unnecessary_import, unused_import

import 'dart:async';
import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:platform_storage/src/native/windows/winrt/helpers.dart';
import 'package:win32/win32.dart'
hide DocumentProperties, WinRTStringConversion;
import 'package:windows_foundation/internal.dart';
import 'package:windows_foundation/windows_foundation.dart';

import 'passwordcredential.dart';

/// @nodoc
const IID_ICredentialFactory = '{54ef13a1-bf26-47b5-97dd-de779b7cad58}';

class ICredentialFactory extends IInspectable {
ICredentialFactory.fromPtr(super.ptr)
: _vtable = ptr.ref.vtable.cast<_ICredentialFactoryVtbl>().ref;

final _ICredentialFactoryVtbl _vtable;

factory ICredentialFactory.from(IInspectable interface) =>
interface.cast(ICredentialFactory.fromPtr, IID_ICredentialFactory);

PasswordCredential createPasswordCredential(
String resource, String userName, String password) {
final credential = calloc<COMObject>();

final hr = _vtable.CreatePasswordCredential.asFunction<
int Function(VTablePointer lpVtbl, int resource, int userName,
int password, Pointer<COMObject> credential)>()(
lpVtbl,
resource.toHString(),
userName.toHString(),
password.toHString(),
credential);

if (FAILED(hr)) {
free(credential);
throwWindowsException(hr);
}

return PasswordCredential.fromPtr(credential);
}
}

final class _ICredentialFactoryVtbl extends Struct {
external IInspectableVtbl baseVtbl;
external Pointer<
NativeFunction<
HRESULT Function(
VTablePointer lpVtbl,
IntPtr resource,
IntPtr userName,
IntPtr password,
Pointer<COMObject> credential)>> CreatePasswordCredential;
}
Loading

0 comments on commit 04dd90c

Please sign in to comment.