Skip to content

Commit 6b189aa

Browse files
author
Ivan Dlugos
committed
add object browser support
1 parent 9dad5d6 commit 6b189aa

File tree

7 files changed

+127
-0
lines changed

7 files changed

+127
-0
lines changed

objectbox/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## latest
22

33
* Add `Query.findUnique()` to find a single object matching the query.
4+
* Add data `Browser`, see [docs](https://docs.objectbox.io/data-browser) for more details.
45

56
## 1.1.1 (2021-07-09)
67

objectbox/lib/objectbox.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ library objectbox;
66

77
export 'src/annotations.dart';
88
export 'src/box.dart' show Box, PutMode;
9+
export 'src/browser.dart' show Browser;
910
export 'src/common.dart';
1011
export 'src/query.dart'
1112
show

objectbox/lib/src/browser.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'native/browser.dart' if (dart.library.html) 'web/browser.dart';

objectbox/lib/src/native/bindings/bindings.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ late final native_query_close =
122122
_lib!.lookup<NativeFunction<_native_close>>('obx_query_close');
123123
late final native_query_prop_close =
124124
_lib!.lookup<NativeFunction<_native_close>>('obx_query_prop_close');
125+
late final native_browser_close =
126+
_lib!.lookup<NativeFunction<_native_close>>('obx_browser_close');
125127

126128
/// Keeps `this` alive until this call, preventing finalizers to run.
127129
/// Necessary for objects with a finalizer attached because the optimizer may
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import 'dart:ffi';
2+
3+
import 'bindings/bindings.dart';
4+
import 'bindings/helpers.dart';
5+
import 'store.dart';
6+
7+
/// Data browser allows you to explore the DB contents in a regular web browser.
8+
///
9+
/// The Browser runs directly on your device or on your development machine.
10+
/// Behind the scenes this works by bundling a simple HTTP browser into
11+
/// ObjectBox when building your app. If triggered, it will then provide a basic
12+
/// web interface to the data and schema.
13+
class Browser {
14+
late Pointer<OBX_browser> _cBrowser;
15+
late final Pointer<OBX_dart_finalizer> _cFinalizer;
16+
17+
@pragma('vm:prefer-inline')
18+
Pointer<OBX_browser> get _ptr => (_cBrowser.address != 0)
19+
? _cBrowser
20+
: throw StateError('Browser already closed');
21+
22+
/// Whether the loaded ObjectBox native library supports ObjectBrowser.
23+
static bool isAvailable() => C.has_feature(OBXFeature.ObjectBrowser);
24+
25+
/// Creates a sync client associated with the given store and options.
26+
/// This does not initiate any connection attempts yet: call start() to do so.
27+
Browser(Store store, {String bindUri = 'http://127.0.0.1:8090'}) {
28+
if (!isAvailable()) {
29+
throw UnsupportedError(
30+
'ObjectBrowser is not available in the loaded ObjectBox runtime library.');
31+
}
32+
initializeDartAPI();
33+
34+
final opt = checkObxPtr(C.browser_opt());
35+
try {
36+
checkObx(
37+
C.browser_opt_store(opt, InternalStoreAccess.ptr(store), nullptr));
38+
checkObx(C.browser_opt_user_management(opt, false));
39+
withNativeString(bindUri,
40+
(Pointer<Int8> cStr) => checkObx(C.browser_opt_bind(opt, cStr)));
41+
} catch (_) {
42+
C.browser_opt_free(opt);
43+
rethrow;
44+
}
45+
46+
_cBrowser = C.browser(opt);
47+
48+
// Keep the finalizer so we can detach it when close() is called manually.
49+
_cFinalizer = C.dartc_attach_finalizer(
50+
this, native_browser_close, _cBrowser.cast(), 1024 * 1024);
51+
if (_cFinalizer == nullptr) {
52+
close();
53+
throwLatestNativeError();
54+
}
55+
}
56+
57+
/// Closes and cleans up all resources used by this ObjectBrowser.
58+
void close() {
59+
if (_cBrowser.address != 0) {
60+
final errors = List.filled(2, 0);
61+
if (_cFinalizer != nullptr) {
62+
errors[0] = C.dartc_detach_finalizer(_cFinalizer, this);
63+
}
64+
errors[1] = C.browser_close(_cBrowser);
65+
_cBrowser = nullptr;
66+
errors.forEach(checkObx);
67+
}
68+
}
69+
70+
/// Returns if the browser is already closed and can no longer be used.
71+
bool isClosed() => _cBrowser.address == 0;
72+
73+
/// Port the Browser listens on. This is especially useful if the port was
74+
/// assigned automatically (a "0" port was used in the [bindUri]).
75+
late final int port = () {
76+
final result = C.browser_port(_ptr);
77+
reachabilityFence(this);
78+
if (result == 0) throwLatestNativeError();
79+
return result;
80+
}();
81+
}

objectbox/lib/src/web/browser.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

objectbox/test/browser_test.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import 'dart:convert';
2+
import 'dart:io';
3+
4+
import 'package:objectbox/objectbox.dart';
5+
import 'package:test/test.dart';
6+
7+
import 'entity.dart';
8+
import 'test_env.dart';
9+
10+
void main() {
11+
late TestEnv env;
12+
13+
setUp(() {
14+
env = TestEnv('browser');
15+
});
16+
17+
tearDown(() => env.close());
18+
19+
test('browser', () async {
20+
env.box.put(TestEntity.filled());
21+
22+
final browser = Browser(env.store);
23+
24+
// Check that it serves requests and has correct permissions configured.
25+
final response = await HttpClient()
26+
.get('127.0.0.1', browser.port, '/api/v2/auth-info')
27+
.then((request) => request.close());
28+
expect(response.statusCode, 200);
29+
expect(await response.transform(utf8.decoder).join(''),
30+
'{"auth":false,"permissions":{"modelRead":true,"modelWrite":true,"objectsRead":true,"objectsWrite":true,"runtimeRead":true,"runtimeWrite":true}}');
31+
32+
expect(browser.isClosed(), isFalse);
33+
browser.close();
34+
expect(browser.isClosed(), isTrue);
35+
browser.close(); // does nothing
36+
},
37+
skip: Browser.isAvailable()
38+
? null
39+
: 'ObjectBrowser is not available in the loaded library');
40+
}

0 commit comments

Comments
 (0)