Skip to content
This repository has been archived by the owner on Jun 3, 2022. It is now read-only.

Commit

Permalink
Cleans up remote controller class. (#74)
Browse files Browse the repository at this point in the history
* Cleans up Remote. Removes most of the static methods in favor in instance props.

* Updates comments.

* Removes duped code.

* Removes duped code.

* Updates remote when adding variables first time from storage.
  • Loading branch information
chriscox authored Feb 10, 2017
1 parent 7a4847d commit 715812d
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 71 deletions.
30 changes: 16 additions & 14 deletions src/core/Remixer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,16 @@ class Remixer {
* Appends the HTML iFrame to body of client app. Attaches key listener to
* toggle Overlay visibility.
* @static
* @param {{}} remoteConfig The optional firebase configuration. Provide this
* configuration if you wish to use the remote
* controller.
*/
static start(): void {
static start(remoteConfig?: {}): void {
this._sharedInstance.appendFrameToBody();
this._sharedInstance.addKeyListener();
if (remoteConfig) {
Remote.initializeRemote(remoteConfig);
}
}

/**
Expand Down Expand Up @@ -246,15 +252,12 @@ class Remixer {
if (storedVariable) {
// Update variable if exists in storage.
this.updateVariable(variable, storedVariable.selectedValue);
Remote.saveVariable(variable, false);
} else {
// Save variable first time.
this.saveVariable(variable);
variable.executeCallbacks();
}

// Save remotely without throttling. If remote sharing is disabled,
// a call to this method will simply be a no-op.
Remote.saveVariable(variable, false);
}
}

Expand Down Expand Up @@ -320,19 +323,18 @@ class Remixer {
*/
static saveVariable(variable: Variable): void {
LocalStorage.saveVariable(variable);
Remote.saveVariable(variable, true);

// Save remotely. If remote sharing is disabled, a call to this method
// will simply be a no-op.
Remote.saveVariable(variable);
}

/**
* Initializes the remote controller.
*
* A call to this method will allow you to share your Variables to the
* remote controller being hosted as per your firebase configuration.
* @static
* @param {{}} config The firebase credentials.
* Returns the current remote controller class.
* @return {Remote}
*/
static inializeRemote(config: {}): void {
Remote.initializeRemote(config);
get remote(): Remote {
return Remote.attachedInstance;
}
}

Expand Down
1 change: 1 addition & 0 deletions src/lib/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export const StorageKey = {
REMIXER: "__remixer__",
KEY_REMIXER: "remixer",
KEY_REMOTE_ID: "remoteId",
KEY_REMOTE_ENABLED: "remoteEnabled",
KEY_VARIABLES: "variables"
};

Expand Down
1 change: 1 addition & 0 deletions src/lib/LocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export class LocalStorage {

/**
* Retrieves a preference from local storage.
* @static
* @param {string} key The key of the preference to retrieve.
* @return {any} Returns the preference object.
*/
Expand Down
165 changes: 108 additions & 57 deletions src/lib/Remote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,27 +43,57 @@ export class Remote {
*/
private static _sharedInstance = new Remote();

/**
* Provides ability for Remixer HTML iFrame to access this instance of Remote.
* @return {Remote} The attached instance of Remote.
*/
static get attachedInstance(): Remote {
return this._sharedInstance;
}

/**
* Throttles network save calls.
* @private
* @static
* @type {any}
*/
private static _throttledSaveVariable: any;
private _throttledSaveVariable: any;

private _enabled: boolean;

/**
* The remote ID.
* @private
* @type {string}
* Whether the remote controller is enabled.
* @static
* @readonly
* @return {boolean}
*/
private remoteId: string;
get isEnabled(): boolean {
return this._enabled;
}

private _remoteId: string;

/**
* Whether the remote controller is enabled.
* @private
* @type {string}
* Returns the remote controller ID.
* @readonly
* @return {string} The remote controller ID.
*/
private enabled: boolean = false;
get remoteId(): string {
return this._remoteId;
}

/**
* Returns the remote controller URL.
*
* Example URL:
* "https://<PROJECT-ID>.firebaseapp.com/<REMOTE-ID>"
* @readonly
* @return {string} The remote controller URL.
*/
get remoteUrl(): string {
let authDomain = firebase.app().options["authDomain"];
return `https://${authDomain}/${this._remoteId}`;
}

/**
* Initializes the remote controller.
Expand All @@ -76,43 +106,35 @@ export class Remote {
static initializeRemote(config: {}): void {
// Get the locally stored remoteId. If doesn't exist, generate a new one
// and store it.
let storedRemoteId = this.getStoredRemoteId();
let instance = this._sharedInstance;
let storedRemoteId = instance.getPreference(StorageKey.KEY_REMOTE_ID);
if (!storedRemoteId) {
storedRemoteId = this.storeRemoteId(this.generateRemoteId());
storedRemoteId = instance.generateRemoteId();
instance.savePreference(StorageKey.KEY_REMOTE_ID, storedRemoteId);
}
this._sharedInstance.remoteId = storedRemoteId;
firebase.initializeApp(config);
}
instance._remoteId = storedRemoteId;

/**
* Returns the remote id from local storage.
* @private
* @static
* @return {string} Returns the remote id.
*/
private static getStoredRemoteId(): string {
return LocalStorage.getPreference(StorageKey.KEY_REMOTE_ID);
}
// Check if enabled.
let remoteEnabled = instance.getPreference(StorageKey.KEY_REMOTE_ENABLED);
if (!remoteEnabled) {
remoteEnabled = false;
instance.savePreference(StorageKey.KEY_REMOTE_ENABLED, remoteEnabled);
}
instance._enabled = remoteEnabled;

/**
* Stores the remote id to local storage.
* @private
* @static
* @param {string} remoteId The remote id.
* @return {string} Returns the remote id.
*/
private static storeRemoteId(remoteId: string): string {
LocalStorage.savePreference(StorageKey.KEY_REMOTE_ID, remoteId);
return remoteId;
if (remoteEnabled) {
instance.startSharing();
}

firebase.initializeApp(config);
}

/**
* Generates a unique id consisting of 8 chars.
* @private
* @static
* @return {string} Returns the new remote id.
*/
private static generateRemoteId(): string {
private generateRemoteId(): string {
return uuid().substring(0, 8);
}

Expand All @@ -122,25 +144,32 @@ export class Remote {
* @return {firebase.database.Reference} The firebase database reference.
*/
private dbReference(): firebase.database.Reference {
return firebase.database().ref(`${StorageKey.KEY_REMIXER}/${this.remoteId}`);
return firebase.database().ref(`${StorageKey.KEY_REMIXER}/${this._remoteId}`);
}

/**
* Start sharing the variable updates to the remote controller.
* @static
*/
static startSharing(): void {
startSharing(): void {
this._throttledSaveVariable = throttle(this._save, THROTTLE_WAIT);
this._sharedInstance.enabled = true;
this._enabled = true;
this.savePreference(StorageKey.KEY_REMOTE_ENABLED, true);

// Save each variable without throttling.
for (let variable of remixer.attachedInstance.variablesArray) {
Remote.saveVariable(variable, false);
}
}

/**
* Stops sharing the variable updates to the remote controller.
* @static
*/
static stopSharing(): void {
stopSharing(): void {
this._throttledSaveVariable.cancel();
this._sharedInstance.enabled = false;
this.savePreference(StorageKey.KEY_REMOTE_ENABLED, false);
this.stopObservingUpdates();
Remote.removeAllVariables();
this._enabled = false;
}

/**
Expand All @@ -160,20 +189,21 @@ export class Remote {
* @param {boolean = true} Whether to throttle the saves.
*/
static saveVariable(variable: Variable, throttle: boolean = true): void {
if (this._sharedInstance.enabled) {
if (this._sharedInstance._enabled) {
if (throttle) {
this._throttledSaveVariable(variable);
this._sharedInstance._throttledSaveVariable(variable);
} else {
this._save(variable);
this._sharedInstance._save(variable);
}
}
}

/**
* Removes all variables remotely.
* @static
*/
static removeAllVariables(): void {
if (this._sharedInstance.enabled) {
if (this._sharedInstance._enabled) {
this._sharedInstance.dbReference().remove();
}
}
Expand All @@ -184,25 +214,23 @@ export class Remote {
* When saving to remote, we first stop observing updates then restart after
* the update. This prevents a cyclical error of network and local changes.
* @private
* @static
* @param {Variable} variable The variable to save.
*/
private static _save(variable: Variable): void {
if (this._sharedInstance.enabled) {
private _save(variable: Variable): void {
if (this._enabled) {
this.stopObservingUpdates(variable.key);
this._sharedInstance.dbReference().child(variable.key).set(variable.serialize());
this.dbReference().child(variable.key).set(variable.serialize());
this.startObservingUpdates(variable.key);
}
}

/**
* Starts a listener for any changes received for a variable.
* @private
* @static
* @param {string} variableKey The variable key.
*/
private static startObservingUpdates(variableKey: string): void {
let reference = this._sharedInstance.dbReference().child(variableKey);
private startObservingUpdates(variableKey: string): void {
let reference = this.dbReference().child(variableKey);
reference.on("child_changed", function(data) {
let variable = remixer.getVariable(data.ref.parent.key);
remixer.cloneAndUpdateVariable(variable, data.val());
Expand All @@ -212,10 +240,33 @@ export class Remote {
/**
* Stops all change listeners for a variable.
* @private
* @static
* @param {string} variableKey The variable key.
* @param {string} variableKey The optional variable key.
*/
private stopObservingUpdates(variableKey?: string): void {
if (variableKey) {
this.dbReference().child(variableKey).off();
} else {
this.dbReference().off();
}
}

/**
* Retrieves a preference from local storage.
* @private
* @param {string} key The key of the preference to retrieve.
* @return {any} Returns the preference object.
*/
private getPreference(key: string): any {
return LocalStorage.getPreference(key);
}

/**
* Saves a preference to local storage.
* @private
* @param {string} key The preference key.
* @param {any} value The preference value.
*/
private static stopObservingUpdates(variableKey: string): void {
this._sharedInstance.dbReference().child(variableKey).off();
private savePreference(key: string, value: any): void {
LocalStorage.savePreference(key, value);
}
}

0 comments on commit 715812d

Please sign in to comment.