| // Copyright 2015 The Vanadium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| /// Since this file includes Sky/Mojo, it will need to be mocked out for unit tests. |
| /// Unfortunately, imports can't be replaced, so the best thing to do is to swap out the whole file. |
| /// |
| /// The goal of the SettingsManager is to handle viewing and editing of the |
| /// Croupier Settings. |
| /// loadSettings: Get the settings of the current player or specified userID. |
| /// saveSettings: For the current player and their userID, save settings. |
| /// In the background, these values will be synced. |
| /// When setting up a sync group, the userIDs are very important. |
| |
| import '../../logic/croupier_settings.dart' as util; |
| import 'croupier_client.dart' show CroupierClient; |
| import 'util.dart' as util; |
| |
| import 'dart:async'; |
| import 'dart:convert' show UTF8, JSON; |
| |
| import 'package:ether/syncbase_client.dart' |
| show SyncbaseNoSqlDatabase, SyncbaseTable, WatchChange, WatchChangeTypes; |
| |
| typedef void updateCallbackT(String key, String value); |
| |
| class SettingsManager { |
| final updateCallbackT updateCallback; |
| final CroupierClient _cc; |
| |
| SyncbaseTable tb; |
| SyncbaseTable tbUser; |
| |
| SettingsManager([this.updateCallback]) : _cc = new CroupierClient(); |
| |
| Future _prepareSettingsTable() async { |
| if (tb != null && tbUser != null) { |
| return; // Then we're already prepared. |
| } |
| |
| SyncbaseNoSqlDatabase db = await _cc.createDatabase(); |
| tb = await _cc.createTable(db, util.tableNameSettings); |
| tbUser = await _cc.createTable(db, util.tableNameSettingsUser); |
| |
| // Start to watch the stream for the shared settings table. |
| Stream<WatchChange> watchStream = |
| db.watch(util.tableNameSettings, '', await db.getResumeMarker()); |
| _startWatch(watchStream); // Don't wait for this future. |
| } |
| |
| Future<String> load([int userID]) async { |
| util.log('SettingsManager.load'); |
| await _prepareSettingsTable(); |
| |
| if (userID == null) { |
| return _tryReadData(tbUser, "settings"); |
| } |
| return _tryReadData(tb, "${userID}"); |
| } |
| |
| Future<String> _tryReadData(SyncbaseTable st, String rowkey) async { |
| var row = st.row(rowkey); |
| if (!(await row.exists())) { |
| print("${rowkey} did not exist"); |
| return null; |
| } |
| return UTF8.decode(await row.get()); |
| } |
| |
| // Since only the current user is allowed to save, we should also save to the |
| // user's personal settings as well. |
| Future save(int userID, String jsonString) async { |
| util.log('SettingsManager.save'); |
| await _prepareSettingsTable(); |
| |
| await tbUser.row("settings").put(UTF8.encode(jsonString)); |
| await tb.row("${userID}").put(UTF8.encode(jsonString)); |
| } |
| |
| Future _startWatch(Stream<WatchChange> watchStream) async { |
| util.log('Settings watching for changes...'); |
| // This stream never really ends, so I guess we'll watch forever. |
| await for (WatchChange wc in watchStream) { |
| assert(wc.tableName == util.tableNameSettings); |
| util.log('Watch Key: ${wc.rowName}'); |
| util.log('Watch Value ${UTF8.decode(wc.valueBytes)}'); |
| String key = wc.rowName; |
| String value; |
| switch (wc.changeType) { |
| case WatchChangeTypes.put: |
| value = UTF8.decode(wc.valueBytes); |
| break; |
| case WatchChangeTypes.delete: |
| value = null; |
| break; |
| default: |
| assert(false); |
| } |
| |
| if (this.updateCallback != null) { |
| this.updateCallback(key, value); |
| } |
| } |
| } |
| } |