Skip to content
Snippets Groups Projects
Verified Commit 8708b47a authored by Pier Angelo Vendrame's avatar Pier Angelo Vendrame :jack_o_lantern:
Browse files

fixup! Bug 40597: Implement TorSettings module

Bug 41114: Refactor TorConnect.

Add a specialized class for every state.
Removed TorConnectStateTransitions and store the valid transitions
inside the new classes.
parent 0c5e98ab
Branches
Tags
1 merge request!938Bug 41114: Fix no-async-promise-executor on TorConnect and general refactor
......@@ -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",
......@@ -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();
}
......@@ -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
......@@ -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 => {
......@@ -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) => {
......@@ -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 => {
......@@ -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
......@@ -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 => {
......@@ -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
......@@ -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()],
])
),
......@@ -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}`
);
......@@ -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) {
......@@ -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
);
},
......@@ -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
);
},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment