Skip to content

Commit

Permalink
new firebase mixin usage
Browse files Browse the repository at this point in the history
  • Loading branch information
alextekartik committed Aug 1, 2024
1 parent f59797e commit 5252402
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 25 deletions.
2 changes: 1 addition & 1 deletion storage/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# tekartik analysis_options extension to pedantic
include: package:tekartik_lints/strict.yaml
include: package:tekartik_lints/package.yaml
15 changes: 2 additions & 13 deletions storage/lib/src/common/storage_service_mixin.dart
Original file line number Diff line number Diff line change
@@ -1,19 +1,8 @@
import 'package:tekartik_firebase/firebase.dart';
import 'package:tekartik_firebase_storage/storage.dart';

mixin StorageServiceMixin implements StorageService {
/// Most implementation need a single instance, keep it in memory!
final _instances = <App, Storage?>{};

T getInstance<T extends Storage?>(App app, T Function() createIfNotFound) {
var instance = _instances[app] as T?;
if (instance == null) {
instance = createIfNotFound();
_instances[app] = instance;
}
return instance!;
}
}
/// Storage service mixin.
mixin StorageServiceMixin implements StorageService {}

/// Find the default storage bucket.
String appOptionsGetStorageBucket(AppOptions options) {
Expand Down
70 changes: 64 additions & 6 deletions storage/lib/src/storage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ import 'package:tekartik_firebase/firebase.dart';

/// Query object for listing files.
class GetFilesOptions {
/// Maximum number of results to return.
final int? maxResults;

/// Filter results to files with this prefix.
final String? prefix;

/// Whether to automatically paginate through results.
final bool autoPaginate;

/// Token to retrieve the next page of results.
final String? pageToken;

/// Default implementation
GetFilesOptions(
{this.maxResults, this.prefix, this.pageToken, this.autoPaginate = true});

Expand All @@ -22,7 +30,7 @@ class GetFilesOptions {
if (pageToken != null) 'pageToken': pageToken
}.toString();

// Copy options
/// Copy options
GetFilesOptions copyWith({
int? maxResults,
String? prefix,
Expand All @@ -40,8 +48,10 @@ class GetFilesOptions {

/// GetFiles response
abstract class GetFilesResponse {
/// List of files
List<File> get files;

/// Next query
GetFilesOptions? get nextQuery;

/// Default implementation
Expand All @@ -67,7 +77,11 @@ class _GetFilesResponse implements GetFilesResponse {
}.toString();
}

mixin StorageMixin implements Storage {
/// Compat
typedef StorageMixin = FirebaseStorageMixin;

/// Storage mixin
mixin FirebaseStorageMixin implements Storage {
@override
Bucket bucket([String? name]) {
throw UnimplementedError();
Expand All @@ -79,8 +93,12 @@ mixin StorageMixin implements Storage {
}
}

/// Compat
typedef Storage = FirebaseStorage;

/// The entrypoint for firebase [Storage].
abstract class Storage {
abstract class FirebaseStorage {
/// Returns the [Bucket] with the given name.
Bucket bucket([String? name]);

/// Returns a new [Reference].
Expand All @@ -92,18 +110,25 @@ abstract class Storage {
Reference ref([String? path]);
}

/// Represents a reference to a Google Cloud Storage object.
abstract class Bucket {
/// Name of the bucket
String get name;

/// Returns a reference to a [File] object.
File file(String path);

/// Returns true if the bucket exists.
Future<bool> exists();

/// Create the bucket if it does not exist.
Future<void> create();

/// List files
Future<GetFilesResponse> getFiles([GetFilesOptions? options]);
}

/// Bucket mixin
mixin BucketMixin implements Bucket {
@override
Future<GetFilesResponse> getFiles([GetFilesOptions? options]) {
Expand All @@ -129,23 +154,34 @@ mixin BucketMixin implements Bucket {
String get name => throw UnimplementedError('name');
}

/// Represents a reference to a Google Cloud Storage object.
abstract class File {
/// Write bytes to the file
Future<void> writeAsBytes(Uint8List bytes);

/// Write text to the file
Future<void> writeAsString(String text);

@Deprecated('Use writeAsBytes or writeAsString')

/// Save content to the file
Future<void> save(/* String | List<int> */ dynamic content);

/// Returns true if the file exists.
Future<bool> exists();

@Deprecated('Use readAsBytes or readAsString')

/// Download the file
Future<Uint8List> download();

/// Read bytes
Future<Uint8List> readAsBytes();

/// Read text
Future<String> readAsString();

/// Delete the file
Future<void> delete();

/// Name of the remote file
Expand All @@ -161,14 +197,19 @@ abstract class File {
Future<FileMetadata> getMetadata();
}

/// File metadata
abstract class FileMetadata {
/// Size of the file in bytes
int get size;

/// Date the file was last updated
DateTime get dateUpdated;

/// MD5 hash of the file
String get md5Hash;
}

/// File metadata mixin
mixin FileMetadataMixin implements FileMetadata {
@override
DateTime get dateUpdated => throw UnimplementedError();
Expand All @@ -180,6 +221,7 @@ mixin FileMetadataMixin implements FileMetadata {
int get size => throw UnimplementedError();
}

/// File mixin
mixin FileMixin implements File {
Uint8List _asUint8List(List<int> data) =>
data is Uint8List ? data : Uint8List.fromList(data);
Expand Down Expand Up @@ -239,8 +281,13 @@ mixin FileMixin implements File {
}
}

abstract class StorageService {
Storage storage(App app);
/// Compat
typedef StorageService = FirebaseStorageService;

/// Firebase storage service
abstract class FirebaseStorageService {
/// Get the storage app product from the app
FirebaseStorage storage(App app);
}

/// Represents a reference to a Google Cloud Storage object. Developers can
Expand All @@ -250,6 +297,7 @@ abstract class Reference {
Future<String> getDownloadUrl();
}

/// Reference mixin
mixin ReferenceMixin implements Reference {
@override
Future<String> getDownloadUrl() {
Expand All @@ -258,13 +306,23 @@ mixin ReferenceMixin implements Reference {
}

/// Storage exception type
enum StorageExceptionType { notFound, other }
enum StorageExceptionType {
/// Not found
notFound,

/// Any other exception
other
}

/// Storage exception
class StorageException implements Exception {
/// Type of the exception
final StorageExceptionType type;

/// Message
final String message;

/// Default constructor
StorageException(this.type, this.message);
@override
String toString() => 'StorageException($type) $message';
Expand Down
3 changes: 3 additions & 0 deletions storage/lib/storage.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export 'package:tekartik_firebase_storage/src/storage.dart'
show
FirebaseStorage,
Storage,
FirebaseStorageMixin,
StorageMixin,
Bucket,
BucketMixin,
Expand All @@ -10,6 +12,7 @@ export 'package:tekartik_firebase_storage/src/storage.dart'
FileMixin,
FileMetadata,
FileMetadataMixin,
FirebaseStorageService,
StorageService,
GetFilesOptions,
GetFilesResponse;
8 changes: 8 additions & 0 deletions storage/lib/utils/link.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import 'package:path/path.dart';

/// A reference to a file in a storage bucket
class StorageFileRef {
/// The bucket name
late final String bucket;

/// The path in the bucket
late final String path;

/// Create a new [StorageFileRef] with the given [bucket] and [path]
StorageFileRef(this.bucket, this.path);

/// Create a new [StorageFileRef] from a [uri]
StorageFileRef.fromLink(Uri uri) {
var parts = uri.pathSegments;
bucket = uri.host;
path = url.joinAll(parts);
}

/// Create a uri
Uri toLink() {
return Uri.parse(url.join('gs://$bucket/$path'));
}
Expand Down
9 changes: 6 additions & 3 deletions storage_browser/lib/src/storage_browser.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import 'package:firebase/firebase.dart' // ignore: deprecated_member_use
as native;
import 'package:tekartik_firebase/firebase.dart';
import 'package:tekartik_firebase/firebase_mixin.dart'; // ignore: implementation_imports
import 'package:tekartik_firebase_browser/src/firebase_browser.dart'; // ignore: implementation_imports
import 'package:tekartik_firebase_storage/storage.dart';

class StorageServiceBrowser
with FirebaseProductServiceMixin<Storage>
with FirebaseProductServiceMixin<FirebaseStorage>
implements StorageService {
@override
Storage storage(App app) {
StorageBrowser storage(App app) {
return getInstance(app, () {
assert(app is AppBrowser, 'invalid firebase app type');
final appBrowser = app as AppBrowser;
Expand All @@ -22,7 +23,9 @@ StorageServiceBrowser? _firebaseStorageServiceBrowser;
StorageService get storageService =>
_firebaseStorageServiceBrowser ??= StorageServiceBrowser();

class StorageBrowser with StorageMixin implements Storage {
class StorageBrowser
with FirebaseAppProductMixin<FirebaseStorage>, StorageMixin
implements Storage {
final native.Storage nativeInstance;

StorageBrowser(this.nativeInstance);
Expand Down
7 changes: 5 additions & 2 deletions storage_fs/lib/src/storage_fs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ import 'package:fs_shim/utils/path.dart';
import 'package:tekartik_common_utils/date_time_utils.dart';
import 'package:tekartik_common_utils/map_utils.dart';
import 'package:tekartik_firebase/firebase.dart';
import 'package:tekartik_firebase/firebase_mixin.dart';
import 'package:tekartik_firebase_local/firebase_local.dart';
import 'package:tekartik_firebase_storage/storage.dart';
import 'package:tekartik_firebase_storage/utils/link.dart';

import 'import.dart';

class StorageServiceFs
with FirebaseProductServiceMixin<Storage>
with FirebaseProductServiceMixin<FirebaseStorage>
implements StorageService {
final fs.FileSystem fileSystem;
final String? basePath;
Expand Down Expand Up @@ -284,7 +285,9 @@ class BucketFs with BucketMixin implements Bucket {
}
}

class StorageFs with StorageMixin implements Storage {
class StorageFs
with FirebaseAppProductMixin<FirebaseStorage>, StorageMixin
implements Storage {
final StorageServiceFs service;
final AppLocal app;

Expand Down

0 comments on commit 5252402

Please sign in to comment.