Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(client): reduce config library surface #2269

Merged
merged 10 commits into from
Nov 14, 2024
Merged

refactor(client): reduce config library surface #2269

merged 10 commits into from
Nov 14, 2024

Conversation

fortuna
Copy link
Collaborator

@fortuna fortuna commented Nov 12, 2024

This PR further reduces the exposed surface of the config library and the dependency of config-specific details, advancing the goal to be config agnostic and allow for new protocols, including Websocket. It follows #2265 and many other previous changes.

In this PR I introduce the concepts of Dynamic and Static ServiceConfig. The parsing function now returns the firstHop in the TunnelConfigJson.

I'm trying to minimize the number of functions we need to implement in Go. It's a huge pain to expose even a single function from Go, since it requires touching all platforms. Electron is particularly bad, as functions are implemented as binary execution in a new process.

I believe I've reached a point where I only need to implement parseTunnelConfig in Go:

  • parseAccessKey is now a thin wrapper around parseTunnelConfig. It can stay that way.
  • validateAccessKey simply calls parseAccessKey
  • getHostFromTransportConfig is deleted
  • getAddressFromTransportConfig is only called from the parseTunnelConfig call tree, so it can move to Go.
  • setTransportConfigHost can be deleted if, for Electron, we resolve the first hop in parseTunnelConfig, and inject it in the returned config. Then the Electron code won't need to do the injection.

Phew! It took many attempts and iterations, but I believe this finally brings me to a place where we can move the config logic to Go!

@fortuna fortuna requested a review from a team as a code owner November 12, 2024 01:36
Copy link
Contributor

@daniellacosse daniellacosse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally looks good, just some clarifying questions before I approve

client/src/www/app/outline_server_repository/config.ts Outdated Show resolved Hide resolved
this.staticTunnelConfig.transport
);
const serviceConfig = parseAccessKey(accessKey);
this.name = name ?? serviceConfig.name;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will this enable people to dynamically set their service name? if so, do we want that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't. The name comes directly from the fragment in the access key, not the Tunnel Config (which is what you fetch for dynamic keys).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh got it.

config.method.data || 'unknown'
);
}
const transport: TransportConfigJson = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm mildly confused now about what types should or should not be given the Json suffix. Is it data that's meant to be consumed by go and opaque to typescript? Or data that's meant to be sent over the network? Not exactly sure

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Json objects are those that must be serialized/deserialized into JSON. They are exchanged with the native code and must not have logic. They are simply a serialization format.

Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a huge leap forward! Thanks.

Comment on lines 24 to 26
export type ServiceConfig = {
readonly name: string;
} & (StaticServiceConfig | DynamicServiceConfig);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since name is common in StaticServiceConfig and DynamicServiceConfig, can we simplify the definition here to export type ServiceConfig = (StaticServiceConfig | DynamicServiceConfig)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

this.tunnelConfigLocation = serviceConfig.transportConfigLocation;
this.displayAddress = '';

if (!serviceConfig.name) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will we override user provided name here?

Suggested change
if (!serviceConfig.name) {
if (!this.name) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed.

Copy link
Collaborator Author

@fortuna fortuna left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments addressed

Comment on lines 24 to 26
export type ServiceConfig = {
readonly name: string;
} & (StaticServiceConfig | DynamicServiceConfig);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

client/src/www/app/outline_server_repository/config.ts Outdated Show resolved Hide resolved
this.staticTunnelConfig.transport
);
const serviceConfig = parseAccessKey(accessKey);
this.name = name ?? serviceConfig.name;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It won't. The name comes directly from the fragment in the access key, not the Tunnel Config (which is what you fetch for dynamic keys).

this.tunnelConfigLocation = serviceConfig.transportConfigLocation;
this.displayAddress = '';

if (!serviceConfig.name) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fixed.

config.method.data || 'unknown'
);
}
const transport: TransportConfigJson = {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Json objects are those that must be serialized/deserialized into JSON. They are exchanged with the native code and must not have logic. They are simply a serialization format.

Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@fortuna fortuna enabled auto-merge (squash) November 13, 2024 23:48
@fortuna fortuna merged commit 49bf053 into master Nov 14, 2024
23 checks passed
@fortuna fortuna deleted the fortuna-clean branch November 14, 2024 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants