This commit is contained in:
thosakwe 2017-06-13 12:55:07 -04:00
parent 4fdae1ace7
commit bde453963b
7 changed files with 227 additions and 1 deletions

44
.gitignore vendored
View file

@ -10,3 +10,47 @@ pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

17
.idea/file_service.iml Normal file
View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/packages" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/file_service.iml" filepath="$PROJECT_DIR$/.idea/file_service.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View file

@ -1,2 +1,23 @@
# file_service
Angel service that persists data to a file on disk.
Angel service that persists data to a file on disk, stored as a JSON list. It uses a simple
mutex to prevent race conditions, and caches contents in memory until changes
are made.
The file will be created on read/write, if it does not already exist.
This package is useful in development, as it prevents you from having to install
an external database to run your server.
When running a multi-threaded server, there is no guarantee that file operations
will be mutually excluded. Thus, try to only use this one a single-threaded server
if possible, or one with very low load.
While not necessarily *slow*, this package makes no promises about performance.
# Usage
```dart
configureServer(Angel app) async {
// Just like a normal service
app.use('/api/todos', new JsonFileService(new File('todos_db.json')));
}
```

120
lib/file_service.dart Normal file
View file

@ -0,0 +1,120 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:pool/pool.dart';
/// Persists in-memory changes to a file on disk.
class JsonFileService extends Service {
FileStat _lastStat;
final Pool _mutex = new Pool(1);
MapService _store;
final File file;
JsonFileService(this.file,
{bool allowRemoveAll: false, bool allowQuery: true}) {
_store = new MapService(
allowRemoveAll: allowRemoveAll == true,
allowQuery: allowQuery != false);
}
_load() async {
if (!await file.exists()) await file.writeAsString(JSON.encode([]));
var stat = await file.stat();
//
if (_lastStat == null ||
stat.modified.millisecondsSinceEpoch >
_lastStat.modified.millisecondsSinceEpoch) {
_lastStat = stat;
var contents = await file.readAsString();
try {
var list = JSON.decode(contents) as List;
_store.items.clear(); // Clear exist in-memory copy
_store.items.addAll(list.map(_revive)); // Insert all new entries
} catch (e) {
print('WARNING: Failed to reload contents of ${file.path}.');
}
}
}
_save() async {
var r = await _mutex.request();
await file.writeAsString(JSON.encode(_store.items.map(_jsonify).toList()));
r.release();
}
@override
Future<List> index([Map params]) async =>
_load().then((_) => _store.index(params));
@override
Future<Map> read(id, [Map params]) =>
_load().then((_) => _store.read(id, params));
@override
Future<Map> create(data, [Map params]) async {
await _load();
_store.items.add(data);
await _save();
return data;
}
@override
Future<Map> remove(id, [Map params]) async {
await _load();
var r = await _store.remove(id, params);
await _save();
return r;
}
@override
Future<Map> update(id, data, [Map params]) async {
await _load();
var r = await _store.update(id, data, params);
await _save();
return r;
}
@override
Future<Map> modify(id, data, [Map params]) async {
await _load();
var r = await _store.update(id, data, params);
await _save();
return r;
}
}
_safeForJson(x) {
if (x is DateTime)
return x.toIso8601String();
else if (x is Map)
return _jsonify(x);
else if (x is num || x is String || x is bool || x == null)
return x;
else if (x is Iterable)
return x.map(_safeForJson).toList();
else
return x.toString();
}
Map _jsonify(Map map) {
return map.keys.fold<Map>({}, (out, k) => out..[k] = _safeForJson(map[k]));
}
_revive(x) {
if (x is Map) {
return x.keys.fold<Map>({}, (out, k) => out..[k] = _revive(x[k]));
} else if (x is Iterable)
return x.map(_revive).toList();
else if (x is String) {
try {
return DateTime.parse(x);
} catch (e) {
return x;
}
} else
return x;
}

10
pubspec.yaml Normal file
View file

@ -0,0 +1,10 @@
name: angel_file_service
version: 1.0.0
description: Angel service that persists data to a file on disk.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/file_service
environment:
sdk: ">=1.19.0"
dependencies:
angel_framework: ^1.0.0-dev
pool: ^1.0.0