Loading toolkit/modules/TorConnect.sys.mjs +103 −93 Original line number Diff line number Diff line Loading @@ -117,52 +117,6 @@ XPCOMUtils.defineLazyGetter( └───────────────────────┘ */ /* Maps allowed state transitions TorConnectStateTransitions[state] maps to an array of allowed states to transition to This is just an encoding of the above transition diagram that we verify at runtime */ const TorConnectStateTransitions = Object.freeze( new Map([ [ TorConnectState.Initial, [ TorConnectState.Disabled, TorConnectState.Bootstrapping, TorConnectState.Configuring, TorConnectState.Error, ], ], [ TorConnectState.Configuring, [ TorConnectState.AutoBootstrapping, TorConnectState.Bootstrapping, TorConnectState.Error, ], ], [ TorConnectState.AutoBootstrapping, [ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ], ], [ TorConnectState.Bootstrapping, [ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ], ], [TorConnectState.Error, [TorConnectState.Configuring]], [TorConnectState.Bootstrapped, [TorConnectState.Configuring]], // terminal states [TorConnectState.Disabled, []], ]) ); /* Topics Notified by the TorConnect module */ export const TorConnectTopics = Object.freeze({ StateChange: "torconnect:state-change", Loading @@ -178,9 +132,8 @@ export const TorConnectTopics = Object.freeze({ // state (for example, from Bootstrapping to Configuring in the event the user // cancels a bootstrap attempt) class StateCallback { constructor(state, callback) { constructor(state) { this._state = state; this._callback = callback; this._init(); } Loading Loading @@ -246,6 +199,23 @@ const debug_sleep = async ms => { }); }; // The initial state doesn't actually do anything, so here is a // skeleton for other states which do perform work class InitialState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.Disabled, TorConnectState.Bootstrapping, TorConnectState.Configuring, TorConnectState.Error, ]); _callback = initialCallback; constructor() { super(TorConnectState.Initial); } } async function initialCallback() { // The initial state doesn't actually do anything, so here is a skeleton for other // states which do perform work Loading Loading @@ -280,6 +250,20 @@ async function initialCallback() { }); } class ConfiguringState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.AutoBootstrapping, TorConnectState.Bootstrapping, TorConnectState.Error, ]); _callback = configuringCallback; constructor() { super(TorConnectState.Configuring); } } async function configuringCallback() { await new Promise(async (resolve, reject) => { this.on_transition = nextState => { Loading @@ -288,6 +272,20 @@ async function configuringCallback() { }); } class BootstrappingState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ]); _callback = bootstrappingCallback; constructor() { super(TorConnectState.Bootstrapping); } } async function bootstrappingCallback() { // wait until bootstrap completes or we get an error await new Promise(async (resolve, reject) => { Loading Loading @@ -404,6 +402,20 @@ async function bootstrappingCallback() { }); } class AutoBootstrappingState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ]); _callback = autoBootstrappingCallback; constructor() { super(TorConnectState.AutoBootstrapping); } } async function autoBootstrappingCallback(countryCode) { await new Promise(async (resolve, reject) => { this.on_transition = nextState => { Loading Loading @@ -621,6 +633,16 @@ async function autoBootstrappingCallback(countryCode) { }); } class BootstrappedState extends StateCallback { allowedTransitions = Object.freeze([TorConnectState.Configuring]); _callback = bootstrappedCallback; constructor() { super(TorConnectState.Bootstrapped); } } async function bootstrappedCallback() { await new Promise((resolve, reject) => { // We may need to leave the bootstrapped state if the tor daemon Loading @@ -633,6 +655,16 @@ async function bootstrappedCallback() { }); } class ErrorState extends StateCallback { allowedTransitions = Object.freeze([TorConnectState.Configuring]); _callback = errorCallback; constructor() { super(TorConnectState.Error); } } async function errorCallback(errorMessage, errorDetails, bootstrappingFailure) { await new Promise((resolve, reject) => { this.on_transition = async nextState => { Loading @@ -654,6 +686,16 @@ async function errorCallback(errorMessage, errorDetails, bootstrappingFailure) { }); } class DisabledState extends StateCallback { allowedTransitions = Object.freeze([]); _callback = disabledCallback; constructor() { super(TorConnectState.DisabledState); } } async function disabledCallback() { await new Promise((resolve, reject) => { // no-op, on_transition not defined because no way to leave Disabled state Loading Loading @@ -789,47 +831,14 @@ export const TorConnect = (() => { on_transition function used to resolve their Promise */ _stateCallbacks: Object.freeze( new Map([ /* Initial is never transitioned to */ [ TorConnectState.Initial, new StateCallback(TorConnectState.Initial, initialCallback), ], /* Configuring */ [ TorConnectState.Configuring, new StateCallback(TorConnectState.Configuring, configuringCallback), ], /* Bootstrapping */ [ TorConnectState.Bootstrapping, new StateCallback( TorConnectState.Bootstrapping, bootstrappingCallback ), ], /* AutoBootstrapping */ [ TorConnectState.AutoBootstrapping, new StateCallback( TorConnectState.AutoBootstrapping, autoBootstrappingCallback ), ], /* Bootstrapped */ [ TorConnectState.Bootstrapped, new StateCallback(TorConnectState.Bootstrapped, bootstrappedCallback), ], /* Error */ [ TorConnectState.Error, new StateCallback(TorConnectState.Error, errorCallback), ], /* Disabled */ [ TorConnectState.Disabled, new StateCallback(TorConnectState.Disabled, disabledCallback), ], // Initial is never transitioned to [TorConnectState.Initial, new InitialState()], [TorConnectState.Configuring, new ConfiguringState()], [TorConnectState.Bootstrapping, new BootstrappingState()], [TorConnectState.AutoBootstrapping, new AutoBootstrappingState()], [TorConnectState.Bootstrapped, new BootstrappedState()], [TorConnectState.Error, new ErrorState()], [TorConnectState.Disabled, new DisabledState()], ]) ), Loading @@ -842,9 +851,10 @@ export const TorConnect = (() => { this._hasEverFailed = true; } const prevState = this._state; const prevCallback = this._callback(prevState); // ensure this is a valid state transition if (!TorConnectStateTransitions.get(prevState)?.includes(newState)) { if (!prevCallback?.allowedTransitions.includes(newState)) { throw Error( `TorConnect: Attempted invalid state transition from ${prevState} to ${newState}` ); Loading @@ -857,7 +867,7 @@ export const TorConnect = (() => { this._state = newState; // call our state function and forward any args this._callback(prevState).transition(newState, ...args); prevCallback.transition(newState, ...args); }, _updateBootstrapStatus(progress, status) { Loading Loading @@ -1001,7 +1011,7 @@ export const TorConnect = (() => { * @param {boolean} */ get canBeginBootstrap() { return TorConnectStateTransitions.get(this.state).includes( return this._callback(this.state)?.allowedTransitions.includes( TorConnectState.Bootstrapping ); }, Loading @@ -1014,7 +1024,7 @@ export const TorConnect = (() => { * @param {boolean} */ get canBeginAutoBootstrap() { return TorConnectStateTransitions.get(this.state).includes( return this._callback(this.state)?.allowedTransitions.includes( TorConnectState.AutoBootstrapping ); }, Loading Loading
toolkit/modules/TorConnect.sys.mjs +103 −93 Original line number Diff line number Diff line Loading @@ -117,52 +117,6 @@ XPCOMUtils.defineLazyGetter( └───────────────────────┘ */ /* Maps allowed state transitions TorConnectStateTransitions[state] maps to an array of allowed states to transition to This is just an encoding of the above transition diagram that we verify at runtime */ const TorConnectStateTransitions = Object.freeze( new Map([ [ TorConnectState.Initial, [ TorConnectState.Disabled, TorConnectState.Bootstrapping, TorConnectState.Configuring, TorConnectState.Error, ], ], [ TorConnectState.Configuring, [ TorConnectState.AutoBootstrapping, TorConnectState.Bootstrapping, TorConnectState.Error, ], ], [ TorConnectState.AutoBootstrapping, [ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ], ], [ TorConnectState.Bootstrapping, [ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ], ], [TorConnectState.Error, [TorConnectState.Configuring]], [TorConnectState.Bootstrapped, [TorConnectState.Configuring]], // terminal states [TorConnectState.Disabled, []], ]) ); /* Topics Notified by the TorConnect module */ export const TorConnectTopics = Object.freeze({ StateChange: "torconnect:state-change", Loading @@ -178,9 +132,8 @@ export const TorConnectTopics = Object.freeze({ // state (for example, from Bootstrapping to Configuring in the event the user // cancels a bootstrap attempt) class StateCallback { constructor(state, callback) { constructor(state) { this._state = state; this._callback = callback; this._init(); } Loading Loading @@ -246,6 +199,23 @@ const debug_sleep = async ms => { }); }; // The initial state doesn't actually do anything, so here is a // skeleton for other states which do perform work class InitialState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.Disabled, TorConnectState.Bootstrapping, TorConnectState.Configuring, TorConnectState.Error, ]); _callback = initialCallback; constructor() { super(TorConnectState.Initial); } } async function initialCallback() { // The initial state doesn't actually do anything, so here is a skeleton for other // states which do perform work Loading Loading @@ -280,6 +250,20 @@ async function initialCallback() { }); } class ConfiguringState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.AutoBootstrapping, TorConnectState.Bootstrapping, TorConnectState.Error, ]); _callback = configuringCallback; constructor() { super(TorConnectState.Configuring); } } async function configuringCallback() { await new Promise(async (resolve, reject) => { this.on_transition = nextState => { Loading @@ -288,6 +272,20 @@ async function configuringCallback() { }); } class BootstrappingState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ]); _callback = bootstrappingCallback; constructor() { super(TorConnectState.Bootstrapping); } } async function bootstrappingCallback() { // wait until bootstrap completes or we get an error await new Promise(async (resolve, reject) => { Loading Loading @@ -404,6 +402,20 @@ async function bootstrappingCallback() { }); } class AutoBootstrappingState extends StateCallback { allowedTransitions = Object.freeze([ TorConnectState.Configuring, TorConnectState.Bootstrapped, TorConnectState.Error, ]); _callback = autoBootstrappingCallback; constructor() { super(TorConnectState.AutoBootstrapping); } } async function autoBootstrappingCallback(countryCode) { await new Promise(async (resolve, reject) => { this.on_transition = nextState => { Loading Loading @@ -621,6 +633,16 @@ async function autoBootstrappingCallback(countryCode) { }); } class BootstrappedState extends StateCallback { allowedTransitions = Object.freeze([TorConnectState.Configuring]); _callback = bootstrappedCallback; constructor() { super(TorConnectState.Bootstrapped); } } async function bootstrappedCallback() { await new Promise((resolve, reject) => { // We may need to leave the bootstrapped state if the tor daemon Loading @@ -633,6 +655,16 @@ async function bootstrappedCallback() { }); } class ErrorState extends StateCallback { allowedTransitions = Object.freeze([TorConnectState.Configuring]); _callback = errorCallback; constructor() { super(TorConnectState.Error); } } async function errorCallback(errorMessage, errorDetails, bootstrappingFailure) { await new Promise((resolve, reject) => { this.on_transition = async nextState => { Loading @@ -654,6 +686,16 @@ async function errorCallback(errorMessage, errorDetails, bootstrappingFailure) { }); } class DisabledState extends StateCallback { allowedTransitions = Object.freeze([]); _callback = disabledCallback; constructor() { super(TorConnectState.DisabledState); } } async function disabledCallback() { await new Promise((resolve, reject) => { // no-op, on_transition not defined because no way to leave Disabled state Loading Loading @@ -789,47 +831,14 @@ export const TorConnect = (() => { on_transition function used to resolve their Promise */ _stateCallbacks: Object.freeze( new Map([ /* Initial is never transitioned to */ [ TorConnectState.Initial, new StateCallback(TorConnectState.Initial, initialCallback), ], /* Configuring */ [ TorConnectState.Configuring, new StateCallback(TorConnectState.Configuring, configuringCallback), ], /* Bootstrapping */ [ TorConnectState.Bootstrapping, new StateCallback( TorConnectState.Bootstrapping, bootstrappingCallback ), ], /* AutoBootstrapping */ [ TorConnectState.AutoBootstrapping, new StateCallback( TorConnectState.AutoBootstrapping, autoBootstrappingCallback ), ], /* Bootstrapped */ [ TorConnectState.Bootstrapped, new StateCallback(TorConnectState.Bootstrapped, bootstrappedCallback), ], /* Error */ [ TorConnectState.Error, new StateCallback(TorConnectState.Error, errorCallback), ], /* Disabled */ [ TorConnectState.Disabled, new StateCallback(TorConnectState.Disabled, disabledCallback), ], // Initial is never transitioned to [TorConnectState.Initial, new InitialState()], [TorConnectState.Configuring, new ConfiguringState()], [TorConnectState.Bootstrapping, new BootstrappingState()], [TorConnectState.AutoBootstrapping, new AutoBootstrappingState()], [TorConnectState.Bootstrapped, new BootstrappedState()], [TorConnectState.Error, new ErrorState()], [TorConnectState.Disabled, new DisabledState()], ]) ), Loading @@ -842,9 +851,10 @@ export const TorConnect = (() => { this._hasEverFailed = true; } const prevState = this._state; const prevCallback = this._callback(prevState); // ensure this is a valid state transition if (!TorConnectStateTransitions.get(prevState)?.includes(newState)) { if (!prevCallback?.allowedTransitions.includes(newState)) { throw Error( `TorConnect: Attempted invalid state transition from ${prevState} to ${newState}` ); Loading @@ -857,7 +867,7 @@ export const TorConnect = (() => { this._state = newState; // call our state function and forward any args this._callback(prevState).transition(newState, ...args); prevCallback.transition(newState, ...args); }, _updateBootstrapStatus(progress, status) { Loading Loading @@ -1001,7 +1011,7 @@ export const TorConnect = (() => { * @param {boolean} */ get canBeginBootstrap() { return TorConnectStateTransitions.get(this.state).includes( return this._callback(this.state)?.allowedTransitions.includes( TorConnectState.Bootstrapping ); }, Loading @@ -1014,7 +1024,7 @@ export const TorConnect = (() => { * @param {boolean} */ get canBeginAutoBootstrap() { return TorConnectStateTransitions.get(this.state).includes( return this._callback(this.state)?.allowedTransitions.includes( TorConnectState.AutoBootstrapping ); }, Loading