morango 0.7.0__py2.py3-none-any.whl → 0.7.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of morango might be problematic. Click here for more details.
- morango/__init__.py +1 -1
- morango/management/commands/cleanupsyncs.py +64 -14
- morango/models/core.py +8 -7
- morango/sync/session.py +11 -0
- morango/sync/syncsession.py +7 -2
- {morango-0.7.0.dist-info → morango-0.7.1.dist-info}/METADATA +9 -7
- {morango-0.7.0.dist-info → morango-0.7.1.dist-info}/RECORD +11 -11
- {morango-0.7.0.dist-info → morango-0.7.1.dist-info}/WHEEL +1 -1
- {morango-0.7.0.dist-info → morango-0.7.1.dist-info}/AUTHORS.md +0 -0
- {morango-0.7.0.dist-info → morango-0.7.1.dist-info}/LICENSE +0 -0
- {morango-0.7.0.dist-info → morango-0.7.1.dist-info}/top_level.txt +0 -0
morango/__init__.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import datetime
|
|
2
2
|
import logging
|
|
3
|
+
import uuid
|
|
3
4
|
|
|
4
5
|
from django.core.management.base import BaseCommand
|
|
5
6
|
from django.db import transaction
|
|
@@ -29,6 +30,36 @@ class Command(BaseCommand):
|
|
|
29
30
|
default=6,
|
|
30
31
|
help="Number of hours of inactivity after which a session should be considered stale",
|
|
31
32
|
)
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"--client-instance-id",
|
|
35
|
+
type=uuid.UUID,
|
|
36
|
+
default=None,
|
|
37
|
+
help="Filters the SyncSession models to those with matching 'client_instance_id'",
|
|
38
|
+
)
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"--server-instance-id",
|
|
41
|
+
type=uuid.UUID,
|
|
42
|
+
default=None,
|
|
43
|
+
help="Filters the SyncSession models to those with matching 'server_instance_id'",
|
|
44
|
+
)
|
|
45
|
+
parser.add_argument(
|
|
46
|
+
"--sync-filter",
|
|
47
|
+
type=str,
|
|
48
|
+
default=None,
|
|
49
|
+
help="Filters the TransferSession models to those with 'filters' starting with 'sync_filter'",
|
|
50
|
+
)
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"--push",
|
|
53
|
+
type=bool,
|
|
54
|
+
default=None,
|
|
55
|
+
help="Filters the TransferSession models to those with 'push' set to True",
|
|
56
|
+
)
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--pull",
|
|
59
|
+
type=bool,
|
|
60
|
+
default=None,
|
|
61
|
+
help="Filters the TransferSession models to those with 'push' set to False",
|
|
62
|
+
)
|
|
32
63
|
|
|
33
64
|
def handle(self, *args, **options):
|
|
34
65
|
|
|
@@ -37,10 +68,17 @@ class Command(BaseCommand):
|
|
|
37
68
|
|
|
38
69
|
sync_sessions = SyncSession.objects.filter(active=True)
|
|
39
70
|
|
|
40
|
-
# if ids arg was passed, filter down sessions to only those IDs
|
|
71
|
+
# if ids arg was passed, filter down sessions to only those IDs
|
|
72
|
+
# if included by expiration filter
|
|
41
73
|
if options["ids"]:
|
|
42
74
|
sync_sessions = sync_sessions.filter(id__in=options["ids"])
|
|
43
75
|
|
|
76
|
+
if options["client_instance_id"]:
|
|
77
|
+
sync_sessions = sync_sessions.filter(client_instance_id=options["client_instance_id"])
|
|
78
|
+
|
|
79
|
+
if options["server_instance_id"]:
|
|
80
|
+
sync_sessions = sync_sessions.filter(server_instance_id=options["server_instance_id"])
|
|
81
|
+
|
|
44
82
|
# retrieve all sessions still marked as active but with no activity since the cutoff
|
|
45
83
|
transfer_sessions = TransferSession.objects.filter(
|
|
46
84
|
sync_session_id__in=sync_sessions.values("id"),
|
|
@@ -48,11 +86,19 @@ class Command(BaseCommand):
|
|
|
48
86
|
last_activity_timestamp__lt=cutoff,
|
|
49
87
|
)
|
|
50
88
|
|
|
89
|
+
if options["sync_filter"]:
|
|
90
|
+
transfer_sessions = transfer_sessions.filter(filter__startswith=options["sync_filter"])
|
|
91
|
+
|
|
92
|
+
if options["push"] and not options["pull"]:
|
|
93
|
+
transfer_sessions = transfer_sessions.filter(push=True)
|
|
94
|
+
|
|
95
|
+
if options["pull"] and not options["push"]:
|
|
96
|
+
transfer_sessions = transfer_sessions.filter(push=False)
|
|
97
|
+
|
|
51
98
|
transfer_count = transfer_sessions.count()
|
|
52
99
|
|
|
53
100
|
# loop over the stale sessions one by one to close them out
|
|
54
|
-
for i in
|
|
55
|
-
transfer_session = transfer_sessions[0]
|
|
101
|
+
for i, transfer_session in enumerate(transfer_sessions):
|
|
56
102
|
logger.info(
|
|
57
103
|
"TransferSession {} of {}: deleting {} Buffers and {} RMC Buffers...".format(
|
|
58
104
|
i + 1,
|
|
@@ -68,17 +114,21 @@ class Command(BaseCommand):
|
|
|
68
114
|
transfer_session.active = False
|
|
69
115
|
transfer_session.save()
|
|
70
116
|
|
|
117
|
+
# in order to close a sync session, it must have no active transfer sessions
|
|
118
|
+
# and must have no activity since the cutoff
|
|
119
|
+
sync_sessions = sync_sessions.filter(
|
|
120
|
+
last_activity_timestamp__lt=cutoff,
|
|
121
|
+
).exclude(
|
|
122
|
+
transfersession__active=True,
|
|
123
|
+
)
|
|
71
124
|
sync_count = sync_sessions.count()
|
|
72
125
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"Closing SyncSession {} of {}".format(
|
|
79
|
-
i + 1,
|
|
80
|
-
sync_count,
|
|
81
|
-
)
|
|
126
|
+
for i, sync_session in enumerate(sync_sessions):
|
|
127
|
+
logger.info(
|
|
128
|
+
"Closing SyncSession {} of {}".format(
|
|
129
|
+
i + 1,
|
|
130
|
+
sync_count,
|
|
82
131
|
)
|
|
83
|
-
|
|
84
|
-
|
|
132
|
+
)
|
|
133
|
+
sync_session.active = False
|
|
134
|
+
sync_session.save()
|
morango/models/core.py
CHANGED
|
@@ -17,6 +17,7 @@ from django.db.models import F
|
|
|
17
17
|
from django.db.models import Func
|
|
18
18
|
from django.db.models import Max
|
|
19
19
|
from django.db.models import Q
|
|
20
|
+
from django.db.models import signals
|
|
20
21
|
from django.db.models import TextField
|
|
21
22
|
from django.db.models import Value
|
|
22
23
|
from django.db.models.deletion import Collector
|
|
@@ -468,13 +469,13 @@ class Store(AbstractStore):
|
|
|
468
469
|
klass_model = syncable_models.get_model(self.profile, self.model_name)
|
|
469
470
|
# if store model marked as deleted, attempt to delete in app layer
|
|
470
471
|
if self.deleted:
|
|
471
|
-
#
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
472
|
+
# Don't differentiate between deletion and hard deletion here,
|
|
473
|
+
# as we don't want to add additional tracking for models in either case,
|
|
474
|
+
# just to actually delete them.
|
|
475
|
+
# Import here to avoid circular import, as the utils module
|
|
476
|
+
# imports core models.
|
|
477
|
+
from morango.sync.utils import mute_signals
|
|
478
|
+
with mute_signals(signals.post_delete):
|
|
478
479
|
klass_model.objects.filter(id=self.id).delete()
|
|
479
480
|
return None, deferred_fks
|
|
480
481
|
else:
|
morango/sync/session.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
3
|
from requests import exceptions
|
|
4
|
+
from morango import __version__
|
|
4
5
|
from requests.sessions import Session
|
|
5
6
|
from requests.utils import super_len
|
|
6
7
|
from requests.packages.urllib3.util.url import parse_url
|
|
7
8
|
|
|
8
9
|
from morango.utils import serialize_capabilities_to_client_request
|
|
10
|
+
from morango.utils import SETTINGS
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
logger = logging.getLogger(__name__)
|
|
@@ -35,6 +37,15 @@ class SessionWrapper(Session):
|
|
|
35
37
|
bytes_sent = 0
|
|
36
38
|
bytes_received = 0
|
|
37
39
|
|
|
40
|
+
def __init__(self):
|
|
41
|
+
super(SessionWrapper, self).__init__()
|
|
42
|
+
user_agent_header = "morango/{}".format(__version__)
|
|
43
|
+
if SETTINGS.CUSTOM_INSTANCE_INFO is not None:
|
|
44
|
+
instances = list(SETTINGS.CUSTOM_INSTANCE_INFO)
|
|
45
|
+
if instances:
|
|
46
|
+
user_agent_header += " " + "{}/{}".format(instances[0], SETTINGS.CUSTOM_INSTANCE_INFO.get(instances[0]))
|
|
47
|
+
self.headers["User-Agent"] = "{} {}".format(user_agent_header, self.headers["User-Agent"])
|
|
48
|
+
|
|
38
49
|
def request(self, method, url, **kwargs):
|
|
39
50
|
response = None
|
|
40
51
|
try:
|
morango/sync/syncsession.py
CHANGED
|
@@ -260,12 +260,16 @@ class NetworkSyncConnection(Connection):
|
|
|
260
260
|
sync_session = SyncSession.objects.create(**data)
|
|
261
261
|
return SyncSessionClient(self, sync_session)
|
|
262
262
|
|
|
263
|
-
def resume_sync_session(self, sync_session_id, chunk_size=None):
|
|
263
|
+
def resume_sync_session(self, sync_session_id, chunk_size=None, ignore_existing_process=False):
|
|
264
264
|
"""
|
|
265
265
|
Resumes an existing sync session given an ID
|
|
266
266
|
|
|
267
267
|
:param sync_session_id: The UUID of the `SyncSession` to resume
|
|
268
268
|
:param chunk_size: An optional parameter specifying the size for each transferred chunk
|
|
269
|
+
:type chunk_size: int
|
|
270
|
+
:param ignore_existing_process:An optional parameter specifying whether to ignore an
|
|
271
|
+
existing active process ID
|
|
272
|
+
:type ignore_existing_process: bool
|
|
269
273
|
:return: A SyncSessionClient instance
|
|
270
274
|
:rtype: SyncSessionClient
|
|
271
275
|
"""
|
|
@@ -281,7 +285,8 @@ class NetworkSyncConnection(Connection):
|
|
|
281
285
|
|
|
282
286
|
# check that process of existing session isn't still running
|
|
283
287
|
if (
|
|
284
|
-
|
|
288
|
+
not ignore_existing_process
|
|
289
|
+
and sync_session.process_id
|
|
285
290
|
and sync_session.process_id != os.getpid()
|
|
286
291
|
and pid_exists(sync_session.process_id)
|
|
287
292
|
):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: morango
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: Pure Python sqlite-based Django DB replication engine.
|
|
5
5
|
Home-page: https://github.com/learningequality/morango
|
|
6
6
|
Author: Learning Equality
|
|
@@ -20,12 +20,14 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
21
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
22
|
Description-Content-Type: text/markdown
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist:
|
|
27
|
-
Requires-Dist:
|
|
28
|
-
Requires-Dist:
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
License-File: AUTHORS.md
|
|
25
|
+
Requires-Dist: django <2,>=1.10
|
|
26
|
+
Requires-Dist: django-mptt <0.10.0
|
|
27
|
+
Requires-Dist: rsa <3.5,>=3.4.2
|
|
28
|
+
Requires-Dist: djangorestframework ==3.9.1
|
|
29
|
+
Requires-Dist: django-ipware <1.2,>=1.1.6
|
|
30
|
+
Requires-Dist: future ==0.16.0
|
|
29
31
|
Requires-Dist: requests
|
|
30
32
|
Requires-Dist: ifcfg
|
|
31
33
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
morango/__init__.py,sha256=
|
|
1
|
+
morango/__init__.py,sha256=4JEWqdXPhqGXLmHDKnCM3ASxeQQ1jNJYFbtMSpnikdQ,190
|
|
2
2
|
morango/apps.py,sha256=qJ0Tu2YmprNC-7iYlOb1OTG-JxRAweHLnbyb5kHlU9U,546
|
|
3
3
|
morango/errors.py,sha256=okjt7FqSHIf3x9SmnmoW6aqNJ_g7Ye3Fx7tuQSNUYEI,1223
|
|
4
4
|
morango/proquint.py,sha256=oHlbNPi7bkqylUhRbq9GbpdtywxU0AXKslJrowcsrqg,3735
|
|
@@ -20,7 +20,7 @@ morango/constants/transfer_stages.py,sha256=nmM-ywKPFcwOICPkHN_1e4xFOWTxwnvb99hr
|
|
|
20
20
|
morango/constants/transfer_statuses.py,sha256=__Reiqxal53Obq-Hch-Ty-HJwlEUZLFSBdRF9ytim0I,510
|
|
21
21
|
morango/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
morango/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
|
-
morango/management/commands/cleanupsyncs.py,sha256=
|
|
23
|
+
morango/management/commands/cleanupsyncs.py,sha256=Huaz8etLNbmW8X-Vy4x1QY801JYln0iyaeUTJF2L3kE,4833
|
|
24
24
|
morango/migrations/0001_initial.py,sha256=ZUmqmw6DneAFBfsfhapyC3cIDneV9zqC7Lws61UN2VA,11933
|
|
25
25
|
morango/migrations/0002_auto_20170511_0400.py,sha256=6gTEf4g56Y6ZvL0UHGK0AQvURPaWuAmpRVKONdP1GH4,2304
|
|
26
26
|
morango/migrations/0003_auto_20170519_0543.py,sha256=ltBTLl130cjwtRao0zw_FXkEWMrGMTRj1mpgpJmaWP0,682
|
|
@@ -47,7 +47,7 @@ morango/migrations/0023_add_instance_id_fields.py,sha256=lgTETXKFcXM1CnNwXb6kqJ3
|
|
|
47
47
|
morango/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
48
|
morango/models/__init__.py,sha256=6sTAlg7gpmX9xRmjw4GPLdjh6_FzZJEN-WEtRBsgGA8,1983
|
|
49
49
|
morango/models/certificates.py,sha256=Kc4aDNJZMp4JQMqdpZDx6zp-qqG_OhAa5n4f-Q605r8,15331
|
|
50
|
-
morango/models/core.py,sha256=
|
|
50
|
+
morango/models/core.py,sha256=64iEy1DTm_gEyJs4L9BQ8m7FTXkVMyawglIuziqrKmc,38940
|
|
51
51
|
morango/models/fsic_utils.py,sha256=B9RM-uPZFvEXWbsPeeit5qA21gKGpA0NkKCLFIdNI_0,7130
|
|
52
52
|
morango/models/manager.py,sha256=fzzX7k8qV5W5dMBb0ASOBNRJRpvQZbEG1hgyuMtzt4g,163
|
|
53
53
|
morango/models/morango_mptt.py,sha256=K_ZF0lRv3EX6n5K5iCSCjDx4qVnMIG_gq9dAyIIQLIU,1024
|
|
@@ -61,17 +61,17 @@ morango/sync/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
61
61
|
morango/sync/context.py,sha256=_gqfE-RfTIn0UMKFeI2snIJEGCbmR_NRl-Ts5u35B7Q,17815
|
|
62
62
|
morango/sync/controller.py,sha256=rcibQcq579hneUef2p41Ze4OCysLI7rVz6FCFIfYiVA,11575
|
|
63
63
|
morango/sync/operations.py,sha256=jDIHPF8IdqoUOer3aaoq9VHcL0-BVeS7-wlMxMHA1-w,69494
|
|
64
|
-
morango/sync/session.py,sha256=
|
|
65
|
-
morango/sync/syncsession.py,sha256=
|
|
64
|
+
morango/sync/session.py,sha256=9CTLhpEPM8q1M_b2HHxouZbzm7vBJoImoqPWqdodgII,3853
|
|
65
|
+
morango/sync/syncsession.py,sha256=82u95pFN68-Fk9fm63q8dueZ4lZyuDsvhtEe3fZFrMI,25479
|
|
66
66
|
morango/sync/utils.py,sha256=BrG8CYVmaAhRNa_HYuPCYSnncskSsW_ig0Cf7xsY2mo,8792
|
|
67
67
|
morango/sync/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
68
|
morango/sync/backends/base.py,sha256=zQP5hOB2Qw0qv0G00LXFHl2GQ3b0bheyujdNVl5rT-8,10867
|
|
69
69
|
morango/sync/backends/postgres.py,sha256=N0IeXN67AkdQKlD20b8LQZ1ocdarapL8pqu8FQAc6lM,19850
|
|
70
70
|
morango/sync/backends/sqlite.py,sha256=vg7kWFIF346-NjVwexYfjYbrrOyzzvcCmk5uUkqhabw,12850
|
|
71
71
|
morango/sync/backends/utils.py,sha256=KaTfj8dKrhRhl6wua2m_jKifmLZ2Kzsd8wPi1NWEtHM,5198
|
|
72
|
-
morango-0.7.
|
|
73
|
-
morango-0.7.
|
|
74
|
-
morango-0.7.
|
|
75
|
-
morango-0.7.
|
|
76
|
-
morango-0.7.
|
|
77
|
-
morango-0.7.
|
|
72
|
+
morango-0.7.1.dist-info/AUTHORS.md,sha256=9Ussd3Fq3RPjHyQT_3AyGss5jiVbn858WQuIBOi1ajI,276
|
|
73
|
+
morango-0.7.1.dist-info/LICENSE,sha256=RkI6MjmrrTKa3aoPAVyk9QdeLZclcrKds6FH3phRSRU,1074
|
|
74
|
+
morango-0.7.1.dist-info/METADATA,sha256=GdViBtA_HnZnDsaz7tPeGjNegrsO4C6FBS1XHwAZ4sg,2555
|
|
75
|
+
morango-0.7.1.dist-info/WHEEL,sha256=-G_t0oGuE7UD0DrSpVZnq1hHMBV9DD2XkS5v7XpmTnk,110
|
|
76
|
+
morango-0.7.1.dist-info/top_level.txt,sha256=pzREWN0EeEq3yHDRast9XI081Ow_rtcm7WV0ZQTlIPY,8
|
|
77
|
+
morango-0.7.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|