aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Gunthorpe <jgg@mellanox.com>2020-05-26 16:58:38 -0300
committerJason Gunthorpe <jgg@mellanox.com>2020-05-28 10:10:40 -0300
commit72b3e5ff5d68d9f70257f9556068cc1e5de23e1c (patch)
tree07b5e4d26eda13d11eef2b17bc94d659a2652651
parent88c8cdb534716a163c28ec13e12c2877cef19e1f (diff)
downloadcloud_mdir_sync-72b3e5ff5d68d9f70257f9556068cc1e5de23e1c.tar.gz
cloud_mdir_sync-72b3e5ff5d68d9f70257f9556068cc1e5de23e1c.tar.bz2
cloud_mdir_sync-72b3e5ff5d68d9f70257f9556068cc1e5de23e1c.zip
Remove cfg.domains
Directly connect the 'account' API objects to their mailbox users through the config language instead of trying to fix it up after the fact with a dictionary. Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
-rw-r--r--cloud_mdir_sync/config.py14
-rw-r--r--cloud_mdir_sync/gmail.py23
-rw-r--r--cloud_mdir_sync/main.py10
-rw-r--r--cloud_mdir_sync/office365.py50
4 files changed, 42 insertions, 55 deletions
diff --git a/cloud_mdir_sync/config.py b/cloud_mdir_sync/config.py
index be64f57..88a16b6 100644
--- a/cloud_mdir_sync/config.py
+++ b/cloud_mdir_sync/config.py
@@ -16,7 +16,6 @@ logger: logging.Logger
class Config(object):
"""Program configuration and general global state"""
message_db_dir = "~/mail/.cms/"
- domains: Dict[str, Any] = {}
trace_file: Any = None
web_app: "oauth.WebServer"
logger: logging.Logger
@@ -42,6 +41,7 @@ class Config(object):
self._create_logger()
self.cloud_mboxes = []
self.local_mboxes = []
+ self.async_tasks = []
self.message_db_dir = os.path.expanduser(self.message_db_dir)
self.direct_message = self._direct_message
@@ -83,27 +83,31 @@ class Config(object):
then the browser will prompt for the user and the choice will be
cached. To lock the account to a single tenant specify the Azure
Directory name, ie 'contoso.onmicrosoft.com', or the GUID."""
- return (user,tenant)
+ from .office365 import GraphAPI
+ self.async_tasks.append(GraphAPI(self, user, tenant))
+ return self.async_tasks[-1]
def Office365(self, mailbox, account):
"""Create a cloud mailbox for Office365. Mailbox is the name of O365
mailbox to use, account should be the result of Office365_Account"""
from .office365 import O365Mailbox
self.cloud_mboxes.append(
- O365Mailbox(self, mailbox, user=account[0], tenant=account[1]))
+ O365Mailbox(self, mailbox, account))
return self.cloud_mboxes[-1]
def GMail_Account(self, user):
"""Define a GMail account credential. The user must be specified as a
fully qualified Google Account email address. This supports both
consumer GMail accounts, and accounts linked to a G-Suite account."""
- return (user,)
+ from .gmail import GmailAPI
+ self.async_tasks.append(GmailAPI(self, user))
+ return self.async_tasks[-1]
def GMail(self, label, account):
"""Create a cloud mailbox for Office365. Mailbox is the name of O365
mailbox to use, account should be the result of Office365_Account"""
from .gmail import GMailMailbox
- self.cloud_mboxes.append(GMailMailbox(self, label, user=account[0]))
+ self.cloud_mboxes.append(GMailMailbox(self, label, account))
return self.cloud_mboxes[-1]
def MailDir(self, directory):
diff --git a/cloud_mdir_sync/gmail.py b/cloud_mdir_sync/gmail.py
index 8b03e66..b22291f 100644
--- a/cloud_mdir_sync/gmail.py
+++ b/cloud_mdir_sync/gmail.py
@@ -118,17 +118,20 @@ class GmailAPI(object):
authenticator = None
headers: Optional[Dict[str, str]] = None
- def __init__(self, cfg: config.Config, domain_id: str, user: str):
- self.domain_id = domain_id
+ def __init__(self, cfg: config.Config, user: str):
+ self.domain_id = f"gmail-{user}"
self.cfg = cfg
self.user = user
+ async def go(self):
+ cfg = self.cfg
+
connector = aiohttp.connector.TCPConnector(limit=20, limit_per_host=5)
self.session = aiohttp.ClientSession(connector=connector,
raise_for_status=False)
self.redirect_url = cfg.web_app.url + "oauth2/gmail"
- self.api_token = cfg.msgdb.get_authenticator(domain_id)
+ self.api_token = cfg.msgdb.get_authenticator(self.domain_id)
self.oauth = requests_oauthlib.OAuth2Session(
client_id=self.client_id,
client=NativePublicApplicationClient(self.client_id),
@@ -350,23 +353,15 @@ class GMailMailbox(mailbox.Mailbox):
history_delta = None
delete_action = "archive" # or delete
- def __init__(self, cfg: config.Config, label: str, user: str):
+ def __init__(self, cfg: config.Config, label: str, gmail: GmailAPI):
super().__init__(cfg)
self.label_name = label
- self.user = user
+ self.gmail = gmail
self.gmail_messages = {}
async def setup_mbox(self):
"""Setup access to the authenticated API domain for this endpoint"""
- cfg = self.cfg
- did = f"gmail-{self.user}"
- self.name = f"{self.user}:{self.label_name}"
- gmail = cfg.domains.get(did)
- if gmail is None:
- self.gmail = GmailAPI(cfg, did, self.user)
- cfg.domains[did] = self.gmail
- else:
- self.gmail = gmail
+ self.name = f"{self.gmail.user}:{self.label_name}"
# Verify the label exists
jmsg = await self.gmail.get_json("v1", f"/users/me/labels")
diff --git a/cloud_mdir_sync/main.py b/cloud_mdir_sync/main.py
index d085dda..1c86b4a 100644
--- a/cloud_mdir_sync/main.py
+++ b/cloud_mdir_sync/main.py
@@ -58,9 +58,9 @@ async def update_cloud_from_local(cfg: config.Config,
async def synchronize_mail(cfg: config.Config):
"""Main synchronizing loop"""
cfg.web_app = oauth.WebServer()
+ cfg.async_tasks.append(cfg.web_app)
try:
- await cfg.web_app.go()
-
+ await asyncio_complete(*(I.go() for I in cfg.async_tasks))
await asyncio_complete(*(mbox.setup_mbox()
for mbox in cfg.all_mboxes()))
@@ -94,10 +94,8 @@ async def synchronize_mail(cfg: config.Config):
cfg.msgdb.cleanup_msgs(msgs)
cfg.logger.debug("Changed event, looping")
finally:
- await asyncio_complete(*(domain.close()
- for domain in cfg.domains.values()))
- cfg.domains = {}
- await cfg.web_app.close()
+ for I in cfg.async_tasks:
+ await I.close()
def main():
diff --git a/cloud_mdir_sync/office365.py b/cloud_mdir_sync/office365.py
index 3f9ddc7..09d8492 100644
--- a/cloud_mdir_sync/office365.py
+++ b/cloud_mdir_sync/office365.py
@@ -78,37 +78,37 @@ class GraphAPI(object):
owa_token = None
authenticator = None
- def __init__(self, cfg, domain_id, user, tenant):
- import msal
- self.msl_cache = msal.SerializableTokenCache()
- auth = cfg.msgdb.get_authenticator(domain_id)
- if auth is not None:
- self.msl_cache.deserialize(auth)
-
- self.domain_id = domain_id
+ def __init__(self, cfg: config.Config, user: str, tenant: str):
+ self.domain_id = f"o365-{user}-{tenant}"
self.cfg = cfg
self.user = user
- self.web_app = cfg.web_app
+ self.tenant = tenant
if self.user is not None:
self.name = f"{self.user}//{tenant}"
else:
self.name = f"//{tenant}"
- connector = aiohttp.connector.TCPConnector(limit=20, limit_per_host=5)
- self.session = aiohttp.ClientSession(connector=connector,
- raise_for_status=False)
- self.headers = {}
- self.owa_headers = {}
-
# Use the new format much more immutable ids, this will work better
# with our caching scheme. See
# https://docs.microsoft.com/en-us/graph/outlook-immutable-id
- self.headers["Prefer"] = 'IdType="ImmutableId"'
+ self.headers= {"Prefer": 'IdType="ImmutableId"'}
+ self.owa_headers = {}
+
+ async def go(self):
+ import msal
+ self.msl_cache = msal.SerializableTokenCache()
+ auth = self.cfg.msgdb.get_authenticator(self.domain_id)
+ if auth is not None:
+ self.msl_cache.deserialize(auth)
+
+ connector = aiohttp.connector.TCPConnector(limit=20, limit_per_host=5)
+ self.session = aiohttp.ClientSession(connector=connector,
+ raise_for_status=False)
self.msal = msal.PublicClientApplication(
client_id="122f4826-adf9-465d-8e84-e9d00bc9f234",
- authority=f"https://login.microsoftonline.com/{tenant}",
+ authority=f"https://login.microsoftonline.com/{self.tenant}",
token_cache=self.msl_cache)
def _cached_authenticate(self):
@@ -150,7 +150,7 @@ class GraphAPI(object):
self.graph_token = None
self.owa_token = None
- redirect_url = self.web_app.url + "oauth2/msal"
+ redirect_url = self.cfg.web_app.url + "oauth2/msal"
state = hex(id(self)) + secrets.token_urlsafe(8)
url = self.msal.get_authorization_request_url(
scopes=self.graph_scopes + self.owa_scopes,
@@ -369,25 +369,15 @@ class O365Mailbox(mailbox.Mailbox):
def __init__(self,
cfg: config.Config,
mailbox: str,
- user: Optional[str] = None,
- tenant="common"):
+ graph: GraphAPI):
super().__init__(cfg)
self.mailbox = mailbox
- self.tenant = tenant
- self.user = user
+ self.graph = graph
async def setup_mbox(self):
"""Setup access to the authenticated API domain for this endpoint"""
cfg = self.cfg
self.loop = cfg.loop
- did = f"o365-{self.user}-{self.tenant}"
- graph = cfg.domains.get(did)
- if graph is None:
- self.graph = GraphAPI(cfg, did, self.user, self.tenant)
- cfg.domains[did] = self.graph
- else:
- self.graph = graph
-
self.name = f"{self.graph.name}:{self.mailbox}"
json = await self.graph.get_json(