Tidy up ClientService API a bit

Require endpoint to always be present so it is never null, and hence
passed in through account creation. Rename props to be a bit more
descriptive.
This commit is contained in:
Michael Gratton 2018-12-27 10:20:58 +10:30
parent e794c8522c
commit 95ebdd65d2
11 changed files with 120 additions and 84 deletions

View file

@ -831,8 +831,8 @@ public class GearyController : Geary.BaseObject {
// they agreed to both, try again // they agreed to both, try again
Geary.Account account = this.accounts.get(config).account; Geary.Account account = this.accounts.get(config).account;
if (imap_prompted && smtp_prompted if (imap_prompted && smtp_prompted
&& account.incoming.endpoint.is_trusted_or_never_connected && account.incoming.remote.is_trusted_or_never_connected
&& account.outgoing.endpoint.is_trusted_or_never_connected) { && account.outgoing.remote.is_trusted_or_never_connected) {
retry_required = true; retry_required = true;
} else if (validation_result == Geary.Engine.ValidationResult.OK) { } else if (validation_result == Geary.Engine.ValidationResult.OK) {
retry_required = true; retry_required = true;
@ -2893,10 +2893,10 @@ public class GearyController : Geary.BaseObject {
Geary.Endpoint? endpoint = null; Geary.Endpoint? endpoint = null;
switch (service.protocol) { switch (service.protocol) {
case Geary.Protocol.IMAP: case Geary.Protocol.IMAP:
endpoint = account.incoming.endpoint; endpoint = account.incoming.remote;
break; break;
case Geary.Protocol.SMTP: case Geary.Protocol.SMTP:
endpoint = account.outgoing.endpoint; endpoint = account.outgoing.remote;
break; break;
} }
return endpoint; return endpoint;

View file

@ -18,28 +18,30 @@ public abstract class Geary.ClientService : BaseObject {
/** /**
* The configuration for the account the service belongs to. * The service's account.
*/ */
public AccountInformation account { get; private set; } public AccountInformation account { get; private set; }
/** /**
* The configuration for the service. * The configuration for the service.
*/ */
public ServiceInformation service { get; private set; } public ServiceInformation configuration { get; private set; }
/** /**
* The network endpoint the service will connect to. * The network endpoint the service will connect to.
*/ */
public Endpoint? endpoint { get; private set; default = null; } public Endpoint remote { get; private set; }
/** Determines if this manager has been started. */ /** Determines if this manager has been started. */
public bool is_running { get; protected set; default = false; } public bool is_running { get; protected set; default = false; }
protected ClientService(AccountInformation account, protected ClientService(AccountInformation account,
ServiceInformation service) { ServiceInformation configuration,
Endpoint remote) {
this.account = account; this.account = account;
this.service = service; this.configuration = configuration;
this.remote = remote;
} }
/** /**
@ -52,23 +54,20 @@ public abstract class Geary.ClientService : BaseObject {
public async void set_endpoint_restart(Endpoint endpoint, public async void set_endpoint_restart(Endpoint endpoint,
GLib.Cancellable? cancellable = null) GLib.Cancellable? cancellable = null)
throws GLib.Error { throws GLib.Error {
if ((this.endpoint == null && endpoint != null) || if (this.remote != null) {
(this.endpoint != null && this.endpoint.equal_to(endpoint))) { this.remote.untrusted_host.disconnect(on_untrusted_host);
if (this.endpoint != null) { }
this.endpoint.untrusted_host.disconnect(on_untrusted_host);
}
bool do_restart = this.is_running; bool do_restart = this.is_running;
if (do_restart) { if (do_restart) {
yield stop(cancellable); yield stop(cancellable);
} }
this.endpoint = endpoint; this.remote = remote;
this.endpoint.untrusted_host.connect(on_untrusted_host); this.remote.untrusted_host.connect(on_untrusted_host);
if (do_restart) { if (do_restart) {
yield start(cancellable); yield start(cancellable);
}
} }
} }
@ -92,7 +91,7 @@ public abstract class Geary.ClientService : BaseObject {
private void on_untrusted_host(TlsNegotiationMethod method, private void on_untrusted_host(TlsNegotiationMethod method,
GLib.TlsConnection cx) { GLib.TlsConnection cx) {
this.account.untrusted_host(this.service, method, cx); this.account.untrusted_host(this.configuration, method, cx);
} }
} }

View file

@ -352,38 +352,44 @@ public class Geary.Engine : BaseObject {
if (account_instances.has_key(config.id)) if (account_instances.has_key(config.id))
return account_instances.get(config.id); return account_instances.get(config.id);
ImapDB.Account local = new ImapDB.Account(config);
Endpoint incoming_remote = get_shared_endpoint(
config.service_provider, config.incoming
);
Endpoint outgoing_remote = get_shared_endpoint(
config.service_provider, config.outgoing
);
Geary.Account account; Geary.Account account;
switch (config.service_provider) { switch (config.service_provider) {
case ServiceProvider.GMAIL: case ServiceProvider.GMAIL:
account = new ImapEngine.GmailAccount(config); account = new ImapEngine.GmailAccount(
config, local, incoming_remote, outgoing_remote
);
break; break;
case ServiceProvider.YAHOO: case ServiceProvider.YAHOO:
account = new ImapEngine.YahooAccount(config); account = new ImapEngine.YahooAccount(
config, local, incoming_remote, outgoing_remote
);
break; break;
case ServiceProvider.OUTLOOK: case ServiceProvider.OUTLOOK:
account = new ImapEngine.OutlookAccount(config); account = new ImapEngine.OutlookAccount(
config, local, incoming_remote, outgoing_remote
);
break; break;
case ServiceProvider.OTHER: case ServiceProvider.OTHER:
account = new ImapEngine.OtherAccount(config); account = new ImapEngine.OtherAccount(
config, local, incoming_remote, outgoing_remote
);
break; break;
default: default:
assert_not_reached(); assert_not_reached();
} }
Endpoint incoming = get_shared_endpoint(
config.service_provider, config.incoming
);
account.set_endpoint(account.incoming, incoming);
Endpoint outgoing = get_shared_endpoint(
config.service_provider, config.outgoing
);
account.set_endpoint(account.outgoing, outgoing);
account_instances.set(config.id, account); account_instances.set(config.id, account);
return account; return account;
} }

View file

@ -32,8 +32,11 @@ private class Geary.ImapEngine.GmailAccount : Geary.ImapEngine.GenericAccount {
} }
public GmailAccount(Geary.AccountInformation config) { public GmailAccount(Geary.AccountInformation config,
base(config); ImapDB.Account local,
Endpoint incoming_remote,
Endpoint outgoing_remote) {
base(config, local, incoming_remote, outgoing_remote);
} }
protected override Geary.SpecialFolderType[] get_supported_special_folders() { protected override Geary.SpecialFolderType[] get_supported_special_folders() {

View file

@ -62,19 +62,27 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
new Gee.HashMap<Geary.SpecialFolderType, Gee.List<string>>(); new Gee.HashMap<Geary.SpecialFolderType, Gee.List<string>>();
public GenericAccount(AccountInformation config) { public GenericAccount(AccountInformation config,
ImapDB.Account local,
Endpoint incoming_remote,
Endpoint outgoing_remote) {
base(config); base(config);
this.local = new ImapDB.Account(config); this.local = local;
this.local.contacts_loaded.connect(() => { contacts_loaded(); }); this.local.contacts_loaded.connect(() => { contacts_loaded(); });
this.imap = new Imap.ClientService(config, config.incoming); this.imap = new Imap.ClientService(
config, config.incoming, incoming_remote
);
this.imap.min_pool_size = IMAP_MIN_POOL_SIZE; this.imap.min_pool_size = IMAP_MIN_POOL_SIZE;
this.imap.ready.connect(on_pool_session_ready); this.imap.ready.connect(on_pool_session_ready);
this.imap.connection_failed.connect(on_pool_connection_failed); this.imap.connection_failed.connect(on_pool_connection_failed);
this.imap.login_failed.connect(on_pool_login_failed); this.imap.login_failed.connect(on_pool_login_failed);
this.smtp = new Smtp.ClientService( this.smtp = new Smtp.ClientService(
config, config.outgoing, new Outbox.Folder(this, this.local) config,
config.outgoing,
outgoing_remote,
new Outbox.Folder(this, this.local)
); );
this.smtp.email_sent.connect(on_email_sent); this.smtp.email_sent.connect(on_email_sent);
this.smtp.report_problem.connect(notify_report_problem); this.smtp.report_problem.connect(notify_report_problem);
@ -488,7 +496,7 @@ private abstract class Geary.ImapEngine.GenericAccount : Geary.Account {
// that's supposed to be globally unique... // that's supposed to be globally unique...
Geary.RFC822.Message rfc822 = new Geary.RFC822.Message.from_composed_email( Geary.RFC822.Message rfc822 = new Geary.RFC822.Message.from_composed_email(
composed, GMime.utils_generate_message_id( composed, GMime.utils_generate_message_id(
this.smtp.endpoint.remote_address.hostname this.smtp.remote.remote_address.hostname
)); ));
yield this.smtp.queue_email(rfc822, cancellable); yield this.smtp.queue_email(rfc822, cancellable);

View file

@ -7,8 +7,11 @@
private class Geary.ImapEngine.OtherAccount : Geary.ImapEngine.GenericAccount { private class Geary.ImapEngine.OtherAccount : Geary.ImapEngine.GenericAccount {
public OtherAccount(AccountInformation config) { public OtherAccount(AccountInformation config,
base(config); ImapDB.Account local,
Endpoint incoming_remote,
Endpoint outgoing_remote) {
base(config, local, incoming_remote, outgoing_remote);
} }
protected override MinimalFolder new_folder(ImapDB.Folder local_folder) { protected override MinimalFolder new_folder(ImapDB.Folder local_folder) {

View file

@ -24,8 +24,11 @@ private class Geary.ImapEngine.OutlookAccount : Geary.ImapEngine.GenericAccount
} }
public OutlookAccount(AccountInformation config) { public OutlookAccount(AccountInformation config,
base(config); ImapDB.Account local,
Endpoint incoming_remote,
Endpoint outgoing_remote) {
base(config, local, incoming_remote, outgoing_remote);
} }
protected override MinimalFolder new_folder(ImapDB.Folder local_folder) { protected override MinimalFolder new_folder(ImapDB.Folder local_folder) {

View file

@ -27,8 +27,11 @@ private class Geary.ImapEngine.YahooAccount : Geary.ImapEngine.GenericAccount {
} }
public YahooAccount(AccountInformation config) { public YahooAccount(AccountInformation config,
base(config); ImapDB.Account local,
Endpoint incoming_remote,
Endpoint outgoing_remote) {
base(config, local, incoming_remote, outgoing_remote);
if (special_map == null) { if (special_map == null) {
special_map = new Gee.HashMap<Geary.FolderPath, Geary.SpecialFolderType>(); special_map = new Gee.HashMap<Geary.FolderPath, Geary.SpecialFolderType>();

View file

@ -125,8 +125,9 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
public ClientService(AccountInformation account, public ClientService(AccountInformation account,
ServiceInformation service) { ServiceInformation service,
base(account, service); Endpoint remote) {
base(account, service, remote);
this.pool_start = new TimeoutManager.seconds( this.pool_start = new TimeoutManager.seconds(
POOL_START_TIMEOUT_SEC, POOL_START_TIMEOUT_SEC,
@ -154,20 +155,20 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
this.authentication_failed = false; this.authentication_failed = false;
this.pool_cancellable = new Cancellable(); this.pool_cancellable = new Cancellable();
this.endpoint.notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].connect( this.remote.notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].connect(
on_imap_trust_untrusted_host on_imap_trust_untrusted_host
); );
this.endpoint.untrusted_host.connect(on_imap_untrusted_host); this.remote.untrusted_host.connect(on_imap_untrusted_host);
this.endpoint.connectivity.notify["is-reachable"].connect( this.remote.connectivity.notify["is-reachable"].connect(
on_connectivity_change on_connectivity_change
); );
this.endpoint.connectivity.address_error_reported.connect( this.remote.connectivity.address_error_reported.connect(
on_connectivity_error on_connectivity_error
); );
if (this.endpoint.connectivity.is_reachable.is_certain()) { if (this.remote.connectivity.is_reachable.is_certain()) {
this.check_pool.begin(); this.check_pool.begin();
} else { } else {
this.endpoint.connectivity.check_reachable.begin(); this.remote.connectivity.check_reachable.begin();
} }
} }
@ -183,14 +184,14 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
this.is_running = false; this.is_running = false;
this.pool_cancellable.cancel(); this.pool_cancellable.cancel();
this.endpoint.notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].disconnect( this.remote.notify[Endpoint.PROP_TRUST_UNTRUSTED_HOST].disconnect(
on_imap_trust_untrusted_host on_imap_trust_untrusted_host
); );
this.endpoint.untrusted_host.disconnect(on_imap_untrusted_host); this.remote.untrusted_host.disconnect(on_imap_untrusted_host);
this.endpoint.connectivity.notify["is-reachable"].disconnect( this.remote.connectivity.notify["is-reachable"].disconnect(
on_connectivity_change on_connectivity_change
); );
this.endpoint.connectivity.address_error_reported.disconnect( this.remote.connectivity.address_error_reported.disconnect(
on_connectivity_error on_connectivity_error
); );
@ -238,10 +239,10 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
throw new ImapError.UNAUTHENTICATED("Invalid ClientSessionManager credentials"); throw new ImapError.UNAUTHENTICATED("Invalid ClientSessionManager credentials");
if (this.untrusted_host) if (this.untrusted_host)
throw new ImapError.UNAVAILABLE("Untrusted host %s", endpoint.to_string()); throw new ImapError.UNAVAILABLE("Untrusted host %s", remote.to_string());
if (!this.endpoint.connectivity.is_reachable.is_certain()) if (!this.remote.connectivity.is_reachable.is_certain())
throw new ImapError.UNAVAILABLE("Host at %s is unreachable", endpoint.to_string()); throw new ImapError.UNAVAILABLE("Host at %s is unreachable", remote.to_string());
ClientSession? claimed = null; ClientSession? claimed = null;
while (claimed == null) { while (claimed == null) {
@ -330,7 +331,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
if (this.is_running && if (this.is_running &&
!this.authentication_failed && !this.authentication_failed &&
!this.untrusted_host && !this.untrusted_host &&
this.endpoint.connectivity.is_reachable.is_certain()) { this.remote.connectivity.is_reachable.is_certain()) {
int needed = this.min_pool_size - this.all_sessions.size; int needed = this.min_pool_size - this.all_sessions.size;
if (needed <= 0 && is_claiming) { if (needed <= 0 && is_claiming) {
@ -424,7 +425,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
private async ClientSession create_new_authorized_session(Cancellable? cancellable) throws Error { private async ClientSession create_new_authorized_session(Cancellable? cancellable) throws Error {
debug("[%s] Opening new session", this.account.id); debug("[%s] Opening new session", this.account.id);
ClientSession new_session = new ClientSession(endpoint); ClientSession new_session = new ClientSession(remote);
// Listen for auth failures early so the client is notified if // Listen for auth failures early so the client is notified if
// there is an error, even though we won't want to keep the // there is an error, even though we won't want to keep the
@ -442,7 +443,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
try { try {
yield new_session.initiate_session_async( yield new_session.initiate_session_async(
this.service.credentials, cancellable this.configuration.credentials, cancellable
); );
} catch (Error err) { } catch (Error err) {
if (!(err is IOError.CANCELLED)) { if (!(err is IOError.CANCELLED)) {
@ -571,7 +572,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
private void on_imap_trust_untrusted_host() { private void on_imap_trust_untrusted_host() {
// fired when the trust_untrusted_host property changes, indicating if the user has agreed // fired when the trust_untrusted_host property changes, indicating if the user has agreed
// to ignore the trust problems and continue connecting // to ignore the trust problems and continue connecting
if (untrusted_host && endpoint.trust_untrusted_host == Trillian.TRUE) { if (untrusted_host && remote.trust_untrusted_host == Trillian.TRUE) {
untrusted_host = false; untrusted_host = false;
if (this.is_running) { if (this.is_running) {
@ -581,7 +582,7 @@ internal class Geary.Imap.ClientService : Geary.ClientService {
} }
private void on_connectivity_change() { private void on_connectivity_change() {
bool is_reachable = this.endpoint.connectivity.is_reachable.is_certain(); bool is_reachable = this.remote.connectivity.is_reachable.is_certain();
if (is_reachable) { if (is_reachable) {
this.pool_start.start(); this.pool_start.start();
this.pool_stop.reset(); this.pool_stop.reset();

View file

@ -52,8 +52,9 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
public ClientService(AccountInformation account, public ClientService(AccountInformation account,
ServiceInformation service, ServiceInformation service,
Endpoint remote,
Outbox.Folder outbox) { Outbox.Folder outbox) {
base(account, service); base(account, service, remote);
this.outbox = outbox; this.outbox = outbox;
} }
@ -65,13 +66,13 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
this.is_running = true; this.is_running = true;
yield this.outbox.open_async(Folder.OpenFlags.NONE, cancellable); yield this.outbox.open_async(Folder.OpenFlags.NONE, cancellable);
yield this.fill_outbox_queue(cancellable); yield this.fill_outbox_queue(cancellable);
this.endpoint.connectivity.notify["is-reachable"].connect( this.remote.connectivity.notify["is-reachable"].connect(
on_reachable_changed on_reachable_changed
); );
this.endpoint.connectivity.address_error_reported.connect( this.remote.connectivity.address_error_reported.connect(
on_connectivity_error on_connectivity_error
); );
this.endpoint.connectivity.check_reachable.begin(); this.remote.connectivity.check_reachable.begin();
} }
/** /**
@ -79,10 +80,10 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
*/ */
public override async void stop(GLib.Cancellable? cancellable = null) public override async void stop(GLib.Cancellable? cancellable = null)
throws GLib.Error { throws GLib.Error {
this.endpoint.connectivity.notify["is-reachable"].disconnect( this.remote.connectivity.notify["is-reachable"].disconnect(
on_reachable_changed on_reachable_changed
); );
this.endpoint.connectivity.address_error_reported.disconnect( this.remote.connectivity.address_error_reported.disconnect(
on_connectivity_error on_connectivity_error
); );
this.stop_postie(); this.stop_postie();
@ -311,7 +312,7 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
private async void send_email(Geary.RFC822.Message rfc822, Cancellable? cancellable) private async void send_email(Geary.RFC822.Message rfc822, Cancellable? cancellable)
throws Error { throws Error {
Smtp.ClientSession smtp = new Geary.Smtp.ClientSession(this.endpoint); Smtp.ClientSession smtp = new Geary.Smtp.ClientSession(this.remote);
sending_monitor.notify_start(); sending_monitor.notify_start();
@ -408,12 +409,12 @@ internal class Geary.Smtp.ClientService : Geary.ClientService {
private void notify_report_problem(ProblemType problem, Error? err) { private void notify_report_problem(ProblemType problem, Error? err) {
report_problem( report_problem(
new ServiceProblemReport(problem, this.account, this.service, err) new ServiceProblemReport(problem, this.account, this.configuration, err)
); );
} }
private void on_reachable_changed() { private void on_reachable_changed() {
if (this.endpoint.connectivity.is_reachable.is_certain()) { if (this.remote.connectivity.is_reachable.is_certain()) {
start_postie.begin(); start_postie.begin();
} else { } else {
stop_postie(); stop_postie();

View file

@ -34,8 +34,9 @@ public class Geary.MockAccount : Account, MockObject {
public class MockClientService : ClientService { public class MockClientService : ClientService {
public MockClientService(AccountInformation account, public MockClientService(AccountInformation account,
ServiceInformation service) { ServiceInformation configuration,
base(account, service); Endpoint remote) {
base(account, configuration, remote);
} }
public override async void start(GLib.Cancellable? cancellable = null) public override async void start(GLib.Cancellable? cancellable = null)
@ -70,8 +71,16 @@ public class Geary.MockAccount : Account, MockObject {
public MockAccount(AccountInformation config) { public MockAccount(AccountInformation config) {
base(config); base(config);
this._incoming = new MockClientService(config, config.incoming); this._incoming = new MockClientService(
this._outgoing = new MockClientService(config, config.outgoing); config,
config.incoming,
new Endpoint(config.incoming.host, config.incoming.port, 0, 0)
);
this._outgoing = new MockClientService(
config,
config.outgoing,
new Endpoint(config.outgoing.host, config.outgoing.port, 0, 0)
);
} }
public override async void open_async(Cancellable? cancellable = null) throws Error { public override async void open_async(Cancellable? cancellable = null) throws Error {