From 93b0e963140f014eacc74803ea3ec261171845c9 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Mon, 23 May 2022 09:46:40 -0100 Subject: [PATCH 1/5] first draft Signed-off-by: Maxence Lange --- .php_cs.cache | 1 + appinfo/info.xml | 2 +- appinfo/routes.php | 8 +- drafts/federated_sync.md | 493 ++++++++++ lib/CircleSharesManager.php | 243 +++++ lib/CirclesManager.php | 52 +- lib/CirclesQueryHelper.php | 24 +- lib/Command/CirclesDebug.php | 917 ++++++++++++++++++ lib/Controller/DebugController.php | 94 ++ lib/Controller/RemoteController.php | 51 + lib/Controller/SyncController.php | 119 +++ lib/Db/CoreQueryBuilder.php | 78 +- lib/Db/CoreRequestBuilder.php | 40 +- lib/Db/DebugRequest.php | 100 ++ lib/Db/DebugRequestBuilder.php | 116 +++ lib/Db/MemberRequest.php | 21 + lib/Db/SyncedItemLockRequest.php | 61 ++ lib/Db/SyncedItemLockRequestBuilder.php | 117 +++ lib/Db/SyncedItemRequest.php | 100 ++ lib/Db/SyncedItemRequestBuilder.php | 116 +++ ...LockRequest.php => SyncedShareRequest.php} | 53 +- ...lder.php => SyncedShareRequestBuilder.php} | 54 +- .../CircleSharesManagerException.php | 36 + ...ception.php => DebugNotFoundException.php} | 2 +- .../FederatedSyncConflictException.php | 36 + .../FederatedSyncManagerNotFoundException.php | 36 + ...on.php => SyncedItemNotFoundException.php} | 4 +- .../SyncedShareNotFoundException.php | 34 + ... => SyncedSharedAlreadyExistException.php} | 2 +- lib/FederatedItems/CircleSettings.php | 85 -- .../FederatedSync/ShareCreation.php | 228 +++++ lib/FederatedItems/ItemLock.php | 130 --- lib/FederatedItems/SharedItemsSync.php | 4 +- lib/ICircleSharesManager.php | 101 ++ ...eratedItemLimitedToInstanceWithMember.php} | 2 +- lib/IFederatedItemSyncedItem.php | 42 + lib/IFederatedSyncManager.php | 293 ++++++ lib/IReferencedObject.php | 34 + .../Version0025Date20220510104622.php | 243 +++++ lib/Model/Circle.php | 7 +- lib/Model/Debug.php | 277 ++++++ lib/Model/Federated/FederatedEvent.php | 57 +- lib/Model/Federated/RemoteInstance.php | 75 +- lib/Model/Member.php | 5 +- lib/Model/SyncedItem.php | 331 +++++++ lib/Model/SyncedItemLock.php | 228 +++++ lib/Model/SyncedShare.php | 154 +++ lib/Service/ConfigService.php | 3 + lib/Service/DebugService.php | 229 +++++ lib/Service/FederatedEventService.php | 79 +- lib/Service/FederatedShareService.php | 117 --- lib/Service/FederatedSyncItemService.php | 339 +++++++ lib/Service/FederatedSyncService.php | 139 +++ lib/Service/FederatedSyncShareService.php | 313 ++++++ lib/Service/RemoteDownstreamService.php | 28 +- lib/Service/RemoteStreamService.php | 4 + lib/Service/SignedControllerService.php | 314 ++++++ .../ISignedModel.php} | 34 +- lib/Tools/Model/ReferencedDataStore.php | 473 +++++++++ lib/Tools/Traits/TNCSignatory.php | 30 + 60 files changed, 6889 insertions(+), 519 deletions(-) create mode 100644 .php_cs.cache create mode 100644 drafts/federated_sync.md create mode 100644 lib/CircleSharesManager.php create mode 100644 lib/Command/CirclesDebug.php create mode 100644 lib/Controller/DebugController.php create mode 100644 lib/Controller/SyncController.php create mode 100644 lib/Db/DebugRequest.php create mode 100644 lib/Db/DebugRequestBuilder.php create mode 100644 lib/Db/SyncedItemLockRequest.php create mode 100644 lib/Db/SyncedItemLockRequestBuilder.php create mode 100644 lib/Db/SyncedItemRequest.php create mode 100644 lib/Db/SyncedItemRequestBuilder.php rename lib/Db/{ShareLockRequest.php => SyncedShareRequest.php} (56%) rename lib/Db/{ShareLockRequestBuilder.php => SyncedShareRequestBuilder.php} (58%) create mode 100644 lib/Exceptions/CircleSharesManagerException.php rename lib/Exceptions/{FederatedShareBelongingException.php => DebugNotFoundException.php} (94%) create mode 100644 lib/Exceptions/FederatedSyncConflictException.php create mode 100644 lib/Exceptions/FederatedSyncManagerNotFoundException.php rename lib/Exceptions/{FederatedShareAlreadyLockedException.php => SyncedItemNotFoundException.php} (92%) create mode 100644 lib/Exceptions/SyncedShareNotFoundException.php rename lib/Exceptions/{FederatedShareNotFoundException.php => SyncedSharedAlreadyExistException.php} (94%) delete mode 100644 lib/FederatedItems/CircleSettings.php create mode 100644 lib/FederatedItems/FederatedSync/ShareCreation.php delete mode 100644 lib/FederatedItems/ItemLock.php create mode 100644 lib/ICircleSharesManager.php rename lib/{IFederatedItemLimitedToInstanceWithMembership.php => IFederatedItemLimitedToInstanceWithMember.php} (95%) create mode 100644 lib/IFederatedItemSyncedItem.php create mode 100644 lib/IFederatedSyncManager.php create mode 100644 lib/IReferencedObject.php create mode 100644 lib/Migration/Version0025Date20220510104622.php create mode 100644 lib/Model/Debug.php create mode 100644 lib/Model/SyncedItem.php create mode 100644 lib/Model/SyncedItemLock.php create mode 100644 lib/Model/SyncedShare.php create mode 100644 lib/Service/DebugService.php delete mode 100644 lib/Service/FederatedShareService.php create mode 100644 lib/Service/FederatedSyncItemService.php create mode 100644 lib/Service/FederatedSyncService.php create mode 100644 lib/Service/FederatedSyncShareService.php create mode 100644 lib/Service/SignedControllerService.php rename lib/{IFederatedSync.php => Tools/ISignedModel.php} (72%) create mode 100644 lib/Tools/Model/ReferencedDataStore.php diff --git a/.php_cs.cache b/.php_cs.cache new file mode 100644 index 000000000..e9a2bde1e --- /dev/null +++ b/.php_cs.cache @@ -0,0 +1 @@ +{"php":"7.4.28","version":"2.19.3:v2.19.3#75ac86f33fab4714ea5a39a396784d83ae3b5ed8","indent":"\t","lineEnding":"\n","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":{"position_after_anonymous_constructs":"same","position_after_control_structures":"same","position_after_functions_and_oop_constructs":"same"},"class_definition":true,"constant_case":true,"elseif":true,"function_declaration":{"closure_function_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":{"elements":["property","method","const"]},"align_multiline_comment":true,"array_indentation":true,"array_syntax":{"syntax":"short"},"binary_operator_spaces":{"default":"single_space"},"blank_line_after_opening_tag":true,"list_syntax":{"syntax":"short"},"no_unused_imports":true},"hashes":{"files\/list.php":3098306110,"templates\/files\/list.php":3952870293,"tests\/TestSuiteListener.php":2864865747,"tests\/unit\/lib\/Controller\/AdminControllerTest.php":3976347962,"tests\/unit\/lib\/Controller\/LocalControllerTest.php":1858681571,"tests\/unit\/lib\/Api\/CirclesTest.php":3757281238,"tests\/bootstrap.php":3458017747,"lib\/StatusCode.php":1517508866,"lib\/ShareByCircleProvider.php":2660302009,"lib\/Cron\/Maintenance.php":2165319515,"lib\/Cron\/GlobalSync.php":3259630900,"lib\/Cron\/ContactsExistingShares.php":1436358626,"lib\/Listeners\/UserCreated.php":2356192654,"lib\/Listeners\/GroupMemberAdded.php":1309590894,"lib\/Listeners\/GroupDeleted.php":643084160,"lib\/Listeners\/Examples\/ExampleAddingCircleMember.php":2358706464,"lib\/Listeners\/Examples\/ExampleMembershipsRemoved.php":1140636880,"lib\/Listeners\/Examples\/ExampleMembershipsCreated.php":2742947017,"lib\/Listeners\/Examples\/ExampleRequestingCircleMember.php":543434179,"lib\/Listeners\/Notifications\/RequestingMember.php":669805256,"lib\/Listeners\/GroupCreated.php":979770048,"lib\/Listeners\/Files\/AddingMemberSendMail.php":2320983638,"lib\/Listeners\/Files\/MemberAddedSendMail.php":2569100200,"lib\/Listeners\/Files\/CreatingShareSendMail.php":4004922421,"lib\/Listeners\/Files\/RemovingMember.php":1651816727,"lib\/Listeners\/Files\/PreparingMemberSendMail.php":2944165511,"lib\/Listeners\/Files\/ShareCreatedSendMail.php":1984205067,"lib\/Listeners\/Files\/PreparingShareSendMail.php":687968187,"lib\/Listeners\/Files\/DestroyingCircle.php":2272468684,"lib\/Listeners\/Files\/MembershipsRemoved.php":4232695309,"lib\/Listeners\/DeprecatedListener.php":2161897895,"lib\/Listeners\/GroupMemberRemoved.php":1275126808,"lib\/Listeners\/UserDeleted.php":1317516900,"lib\/IFederatedItemHighSeverity.php":1758644050,"lib\/GlobalScale\/MemberJoin.php":1883633825,"lib\/GlobalScale\/MemberRemove.php":284845080,"lib\/GlobalScale\/CircleDestroy.php":331971873,"lib\/GlobalScale\/GlobalSync.php":403207439,"lib\/GlobalScale\/AGlobalScaleEvent.php":1523577386,"lib\/GlobalScale\/CircleCreate.php":518670645,"lib\/GlobalScale\/Test.php":245699567,"lib\/GlobalScale\/CircleUpdate.php":3794135126,"lib\/GlobalScale\/MemberLeave.php":75784237,"lib\/GlobalScale\/MemberUpdate.php":677108294,"lib\/GlobalScale\/UserDeleted.php":1725910468,"lib\/GlobalScale\/FileUnshare.php":1548441625,"lib\/GlobalScale\/FileShare.php":3953187827,"lib\/GlobalScale\/MemberAdd.php":2607375077,"lib\/GlobalScale\/CircleStatus.php":3271681906,"lib\/GlobalScale\/GSMount\/MountManager.php":1320335712,"lib\/GlobalScale\/GSMount\/MountProvider.php":3304612192,"lib\/GlobalScale\/GSMount\/Mount.php":3718785463,"lib\/Service\/SearchService.php":3839171914,"lib\/Service\/EventService.php":2058103507,"lib\/Service\/RemoteDownstreamService.php":1551878007,"lib\/Service\/GSUpstreamService.php":3035168612,"lib\/Service\/RemoteUpstreamService.php":2856176656,"lib\/Service\/EventWrapperService.php":1147557857,"lib\/Service\/OutputService.php":4058852349,"lib\/Service\/GSDownstreamService.php":3698549562,"lib\/Service\/CircleService.php":2569416279,"lib\/Service\/SendMailService.php":3628515164,"lib\/Service\/MemberService.php":2202443321,"lib\/Service\/TimezoneService.php":436192332,"lib\/Service\/GlobalScaleService.php":3633015323,"lib\/Service\/FederatedUserService.php":2865268909,"lib\/Service\/ShareWrapperService.php":3800367712,"lib\/Service\/ContactService.php":1517469205,"lib\/Service\/InterfaceService.php":386071894,"lib\/Service\/ConfigService.php":519972026,"lib\/Service\/FederatedEventService.php":3756840608,"lib\/Service\/RemoteStreamService.php":2304067225,"lib\/Service\/NotificationService.php":3839471957,"lib\/Service\/MigrationService.php":376900923,"lib\/Service\/EventsService.php":1717181588,"lib\/Service\/ShareService.php":3232740508,"lib\/Service\/MembershipService.php":522334436,"lib\/Service\/PermissionService.php":1722876776,"lib\/Service\/MembersService.php":2747321365,"lib\/Service\/MaintenanceService.php":2008565585,"lib\/Service\/MiscService.php":1021072651,"lib\/Service\/FederatedShareService.php":2041740728,"lib\/Service\/GroupsService.php":2974167051,"lib\/Service\/SyncService.php":3373494320,"lib\/Service\/RemoteService.php":3830722518,"lib\/Service\/DavService.php":2842988121,"lib\/Service\/CirclesService.php":272950919,"lib\/Service\/ShareTokenService.php":3839540439,"lib\/Db\/EventWrapperRequestBuilder.php":1086415118,"lib\/Db\/AccountsRequest.php":3482160173,"lib\/Db\/FederatedLinksRequestBuilder.php":2656064863,"lib\/Db\/RemoteRequestBuilder.php":227744767,"lib\/Db\/CoreQueryBuilder.php":2313020751,"lib\/Db\/CircleRequestBuilder.php":1106369364,"lib\/Db\/ShareTokenRequest.php":4192031480,"lib\/Db\/CircleRequest.php":3039949294,"lib\/Db\/CircleProviderRequest.php":3817630890,"lib\/Db\/EventWrapperRequest.php":2884795734,"lib\/Db\/ShareLockRequest.php":4201457145,"lib\/Db\/CircleProviderRequestBuilder.php":2804195879,"lib\/Db\/DeprecatedRequestBuilder.php":1990711328,"lib\/Db\/FileSharesRequest.php":2138500987,"lib\/Db\/AccountsRequestBuilder.php":2398896036,"lib\/Db\/DeprecatedMembersRequestBuilder.php":3344575336,"lib\/Db\/GSSharesRequestBuilder.php":1836370644,"lib\/Db\/DeprecatedMembersRequest.php":3503766299,"lib\/Db\/MembershipRequest.php":439722937,"lib\/Db\/DeprecatedCirclesRequest.php":1164055518,"lib\/Db\/MemberRequest.php":3563956248,"lib\/Db\/MountRequest.php":1099753953,"lib\/Db\/GSSharesRequest.php":3658195235,"lib\/Db\/MemberRequestBuilder.php":3291166456,"lib\/Db\/ShareLockRequestBuilder.php":1174499547,"lib\/Db\/TokensRequestBuilder.php":2249346642,"lib\/Db\/MembershipRequestBuilder.php":4086277549,"lib\/Db\/CoreRequestBuilder.php":1970316195,"lib\/Db\/RemoteRequest.php":642979665,"lib\/Db\/FederatedLinksRequest.php":1198900323,"lib\/Db\/FileSharesRequestBuilder.php":3340254850,"lib\/Db\/DeprecatedCirclesRequestBuilder.php":2658765513,"lib\/Db\/MountRequestBuilder.php":2890867244,"lib\/Db\/ShareWrapperRequest.php":360367138,"lib\/Db\/ShareWrapperRequestBuilder.php":2948379969,"lib\/Db\/ShareTokenRequestBuilder.php":2954299403,"lib\/Db\/TokensRequest.php":2165524722,"lib\/Exceptions\/MigrationException.php":3135728899,"lib\/Exceptions\/FederatedRemoteCircleDoesNotExistException.php":3724491253,"lib\/Exceptions\/FederatedEventException.php":4268947022,"lib\/Exceptions\/FrontendException.php":3477799826,"lib\/Exceptions\/ShareTokenAlreadyExistException.php":3311853497,"lib\/Exceptions\/FakeException.php":1228679011,"lib\/Exceptions\/FederatedItemConflictException.php":1642080270,"lib\/Exceptions\/TokenDoesNotExistException.php":3986469986,"lib\/Exceptions\/FederatedShareNotFoundException.php":3306044363,"lib\/Exceptions\/FederatedItemRemoteException.php":4133160510,"lib\/Exceptions\/SingleCircleNotFoundException.php":439715431,"lib\/Exceptions\/UnknownFederatedItemException.php":1800942895,"lib\/Exceptions\/FederatedLinkDoesNotExistException.php":950685170,"lib\/Exceptions\/MemberHelperException.php":3308150237,"lib\/Exceptions\/CircleTypeNotValidException.php":3747441818,"lib\/Exceptions\/ConfigNoCircleAvailableException.php":3761163339,"lib\/Exceptions\/RemoteAlreadyExistsException.php":1662956393,"lib\/Exceptions\/FileCacheNotFoundException.php":3921852036,"lib\/Exceptions\/MountPointConstructionException.php":3646808514,"lib\/Exceptions\/MemberLevelException.php":380716406,"lib\/Exceptions\/MembersLimitException.php":2936076078,"lib\/Exceptions\/FederatedRemoteIsDownException.php":2677480615,"lib\/Exceptions\/RemoteCircleException.php":1231134117,"lib\/Exceptions\/ShareWrapperNotFoundException.php":4195344203,"lib\/Exceptions\/FederatedEventDSyncException.php":4032770513,"lib\/Exceptions\/FederatedItemBadRequestException.php":161143109,"lib\/Exceptions\/CircleAlreadyExistsException.php":4093257493,"lib\/Exceptions\/FederatedItemUnauthorizedException.php":1117239920,"lib\/Exceptions\/ShareTokenNotFoundException.php":517851422,"lib\/Exceptions\/MemberAlreadyExistsException.php":1519904708,"lib\/Exceptions\/FederatedCircleStatusUpdateException.php":3495978386,"lib\/Exceptions\/ParseMemberLevelException.php":626527872,"lib\/Exceptions\/JsonException.php":4050075292,"lib\/Exceptions\/CircleNameTooShortException.php":3504410197,"lib\/Exceptions\/FederatedItemException.php":3009723389,"lib\/Exceptions\/OwnerNotFoundException.php":1041683449,"lib\/Exceptions\/BroadcasterIsNotCompatibleException.php":1868665268,"lib\/Exceptions\/FederatedCircleLinkFormatException.php":2559586115,"lib\/Exceptions\/EventWrapperNotFoundException.php":2006798244,"lib\/Exceptions\/NotContactAddressException.php":3882857942,"lib\/Exceptions\/InvalidModelException.php":4248268090,"lib\/Exceptions\/RemoteResourceNotFoundException.php":1419686696,"lib\/Exceptions\/RemoteUidException.php":1906531318,"lib\/Exceptions\/EmailAccountInvalidFormatException.php":205206406,"lib\/Exceptions\/UnknownInterfaceException.php":1710879839,"lib\/Exceptions\/RequestBuilderException.php":3436614428,"lib\/Exceptions\/PayloadDeliveryException.php":1523296073,"lib\/Exceptions\/FederatedItemNotFoundException.php":2519165628,"lib\/Exceptions\/MemberNotFoundException.php":3494615888,"lib\/Exceptions\/ModeratorIsNotHighEnoughException.php":1600152488,"lib\/Exceptions\/MemberIsNotOwnerException.php":279323812,"lib\/Exceptions\/RemoteInstanceException.php":1007113206,"lib\/Exceptions\/FederatedUserException.php":1016160639,"lib\/Exceptions\/CircleTypeDisabledException.php":2509021574,"lib\/Exceptions\/MembershipNotFoundException.php":1478290916,"lib\/Exceptions\/ContactFormatException.php":900862783,"lib\/Exceptions\/CircleTypeIsEmptyException.php":198438215,"lib\/Exceptions\/FederatedRemoteDoesNotAllowException.php":3266751647,"lib\/Exceptions\/JsonNotRequestedException.php":1670599906,"lib\/Exceptions\/FederatedUserNotFoundException.php":1823543263,"lib\/Exceptions\/FederatedLinkCreationException.php":3553406001,"lib\/Exceptions\/SuperSessionException.php":4199586510,"lib\/Exceptions\/NotLocalMemberException.php":3409966422,"lib\/Exceptions\/SharingFrameSourceCannotBeAppCirclesException.php":3162211457,"lib\/Exceptions\/SharingFrameAlreadyExistException.php":1973362236,"lib\/Exceptions\/ApiVersionIncompatibleException.php":466252244,"lib\/Exceptions\/GSKeyException.php":363258347,"lib\/Exceptions\/InitiatorNotConfirmedException.php":2213761202,"lib\/Exceptions\/ContactNotFoundException.php":225495792,"lib\/Exceptions\/ModelException.php":3502810125,"lib\/Exceptions\/MemberCantJoinCircleException.php":1453191618,"lib\/Exceptions\/MountNotFoundException.php":163443323,"lib\/Exceptions\/CircleNotFoundException.php":2091462126,"lib\/Exceptions\/FederatedLinkCircleNotFoundException.php":3106945948,"lib\/Exceptions\/LinkedGroupNotAllowedException.php":530078929,"lib\/Exceptions\/FederatedShareBelongingException.php":154025487,"lib\/Exceptions\/InsufficientPermissionException.php":2624917449,"lib\/Exceptions\/GroupNotFoundException.php":695595798,"lib\/Exceptions\/GlobalScaleDSyncException.php":37698037,"lib\/Exceptions\/GroupCannotBeOwnerException.php":3873200201,"lib\/Exceptions\/UserTypeNotFoundException.php":507301615,"lib\/Exceptions\/GSStatusException.php":3782067941,"lib\/Exceptions\/MemberIsOwnerException.php":26260482,"lib\/Exceptions\/MemberIsNotAdminException.php":1789519602,"lib\/Exceptions\/MemberIsNotModeratorException.php":3142953152,"lib\/Exceptions\/InvalidIdException.php":326696496,"lib\/Exceptions\/FederatedShareAlreadyLockedException.php":2200365589,"lib\/Exceptions\/GroupDoesNotExistException.php":2813605874,"lib\/Exceptions\/CommandMissingArgumentException.php":888054115,"lib\/Exceptions\/UnknownRemoteException.php":906713777,"lib\/Exceptions\/InitiatorNotFoundException.php":3982863268,"lib\/Exceptions\/MemberDoesNotExistException.php":1306729406,"lib\/Exceptions\/MemberIsBlockedException.php":3825208092,"lib\/Exceptions\/FederatedCircleNotAllowedException.php":3825954080,"lib\/Exceptions\/CircleDoesNotExistException.php":4128272286,"lib\/Exceptions\/GlobalScaleEventException.php":3605272841,"lib\/Exceptions\/FederatedLinkUpdateException.php":110716268,"lib\/Exceptions\/RemoteNotFoundException.php":4061282988,"lib\/Exceptions\/FederatedItemServerException.php":3273933160,"lib\/Exceptions\/MissingKeyInArrayException.php":4090709890,"lib\/Exceptions\/SharingFrameDoesNotExistException.php":122635795,"lib\/Exceptions\/FederatedItemForbiddenException.php":4292004348,"lib\/Exceptions\/ContactAddressBookNotFoundException.php":3577466788,"lib\/Exceptions\/MemberTypeCantEditLevelException.php":4230209291,"lib\/Exceptions\/MaintenanceException.php":3331759326,"lib\/Exceptions\/SharingFrameAlreadyDeliveredException.php":1071708694,"lib\/Exceptions\/CircleNameFirstCharException.php":2069577355,"lib\/IFederatedItemMustBeInitializedLocally.php":2985817742,"lib\/IFederatedItemLoopbackTest.php":3603051499,"lib\/Command\/CirclesConfig.php":2488709766,"lib\/Command\/CirclesReport.php":2364648697,"lib\/Command\/CirclesJoin.php":3121495449,"lib\/Command\/CirclesSync.php":2046514547,"lib\/Command\/FixUniqueId.php":296260002,"lib\/Command\/SyncContact.php":344240517,"lib\/Command\/SharesFiles.php":1897893678,"lib\/Command\/CirclesDetails.php":971987540,"lib\/Command\/MembersSearch.php":3614851548,"lib\/Command\/MembersAdd.php":2007173529,"lib\/Command\/CirclesRemote.php":3281019039,"lib\/Command\/CirclesDestroy.php":254004564,"lib\/Command\/CirclesCreate.php":4182130016,"lib\/Command\/MembersList.php":490163638,"lib\/Command\/CirclesLeave.php":3232797054,"lib\/Command\/CirclesTest.php":653579852,"lib\/Command\/MembersRemove.php":2552408237,"lib\/Command\/CirclesList.php":1111882427,"lib\/Command\/MembersDetails.php":3900946282,"lib\/Command\/Groups.php":855176257,"lib\/Command\/CirclesMemberships.php":3289350223,"lib\/Command\/CirclesEdit.php":3117317224,"lib\/Command\/CirclesCheck.php":3164036220,"lib\/Command\/CirclesSetting.php":993767465,"lib\/Command\/CirclesMaintenance.php":4058568107,"lib\/Command\/MembersLevel.php":2854814447,"lib\/IFederatedItemMemberOptional.php":405335139,"lib\/Activity\/ProviderSubjectMember.php":3836737211,"lib\/Activity\/ProviderSubjectGroup.php":71629136,"lib\/Activity\/ProviderParser.php":1325018371,"lib\/Activity\/ProviderSubjectCircle.php":4197460670,"lib\/Activity\/SettingAsNonMember.php":38353465,"lib\/Activity\/ProviderSubjectLink.php":246975354,"lib\/Activity\/SettingAsMember.php":1239138452,"lib\/Activity\/Provider.php":1587460034,"lib\/Activity\/Filter.php":3360568612,"lib\/Activity\/SettingAsModerator.php":1229660981,"lib\/IFederatedSync.php":2126007987,"lib\/IFederatedItemSharedItem.php":3906925967,"lib\/IFederatedItemShareManagement.php":1785366796,"lib\/CirclesManager.php":160574126,"lib\/IFederatedItemInitiatorMembershipNotRequired.php":1517055476,"lib\/ShareByCircleProviderDeprecated.php":2244310573,"lib\/IFederatedItemMemberRequired.php":1936688799,"lib\/Handlers\/WebfingerHandler.php":4056953625,"lib\/Search\/FederatedUsers.php":2283220058,"lib\/Search\/GlobalScaleUsers.php":3287167603,"lib\/Search\/LocalUsers.php":2672740033,"lib\/Search\/Contacts.php":2657873953,"lib\/Search\/LocalGroups.php":655714057,"lib\/IFederatedItemInitiatorCheckNotRequired.php":2323721215,"lib\/IFederatedItemCircleCheckNotRequired.php":2686907469,"lib\/MountManager\/CircleMountManager.php":42382,"lib\/MountManager\/CircleMount.php":3297487901,"lib\/MountManager\/CircleMountProvider.php":3100107888,"lib\/IFederatedItemDataRequestOnly.php":2615199436,"lib\/Circles\/FileSharingBroadcaster.php":3376763357,"lib\/IFederatedUser.php":2664730507,"lib\/IFederatedItemLimitedToInstanceWithMembership.php":790702277,"lib\/UnifiedSearch\/UnifiedSearchResult.php":2647724377,"lib\/UnifiedSearch\/UnifiedSearchProvider.php":887662080,"lib\/AppInfo\/Capabilities.php":1677809034,"lib\/AppInfo\/Application.php":2416266824,"lib\/Collaboration\/v2\/CollaboratorSearchPlugin.php":1989445649,"lib\/IFederatedModel.php":4251218432,"lib\/Migration\/Migration.php":3153592806,"lib\/Migration\/ImportOwncloudCustomGroups.php":1942453221,"lib\/Migration\/Version0022Date20220526111723.php":664705595,"lib\/Migration\/Version0024Date20220203123902.php":415138860,"lib\/Migration\/Version0023Date20211216113101.php":937534026,"lib\/Migration\/Version0024Date20220203123901.php":3038501296,"lib\/Migration\/Version0024Date20220317190331.php":1939137606,"lib\/Migration\/Version0022Date20220703115023.php":2337341183,"lib\/Migration\/Version0022Date20220526113601.php":1773317857,"lib\/FederatedItems\/MemberLevel.php":1233608704,"lib\/FederatedItems\/MemberDisplayName.php":2407238499,"lib\/FederatedItems\/CircleSetting.php":22919417,"lib\/FederatedItems\/CircleConfig.php":1233529358,"lib\/FederatedItems\/CircleEdit.php":1868024238,"lib\/FederatedItems\/MemberRemove.php":3156308056,"lib\/FederatedItems\/CircleDestroy.php":2846866196,"lib\/FederatedItems\/SharedItemsSync.php":4190894639,"lib\/FederatedItems\/MassiveMemberAdd.php":1679750120,"lib\/FederatedItems\/ItemLock.php":2015208856,"lib\/FederatedItems\/Files\/FileUnshare.php":1522956073,"lib\/FederatedItems\/Files\/FileShare.php":2487680888,"lib\/FederatedItems\/CircleCreate.php":2450296473,"lib\/FederatedItems\/CircleLeave.php":306486166,"lib\/FederatedItems\/CircleJoin.php":3611832830,"lib\/FederatedItems\/CircleSettings.php":2388414692,"lib\/FederatedItems\/LoopbackTest.php":304425936,"lib\/FederatedItems\/SingleMemberAdd.php":850252658,"lib\/ISearch.php":120915058,"lib\/Controller\/AdminController.php":2931854213,"lib\/Controller\/RemoteController.php":3729341881,"lib\/Controller\/EventWrapperController.php":853491259,"lib\/Controller\/LocalController.php":3155140627,"lib\/IEntity.php":3181412256,"lib\/IFederatedItem.php":3976108387,"lib\/Notification\/Notifier.php":2608559573,"lib\/Api\/v1\/Circles.php":852660927,"lib\/IFederatedItemMemberCheckNotRequired.php":3452777671,"lib\/Tools\/Db\/ExtendedQueryBuilder.php":2515334429,"lib\/Tools\/Db\/IQueryRow.php":2184964271,"lib\/Tools\/Exceptions\/RequestServerException.php":1035169003,"lib\/Tools\/Exceptions\/MalformedArrayException.php":3718624740,"lib\/Tools\/Exceptions\/InvalidOriginException.php":4000904630,"lib\/Tools\/Exceptions\/RequestContentException.php":1746252892,"lib\/Tools\/Exceptions\/SignatoryException.php":339962206,"lib\/Tools\/Exceptions\/RequestResultSizeException.php":1058757206,"lib\/Tools\/Exceptions\/RowNotFoundException.php":3492704175,"lib\/Tools\/Exceptions\/ItemNotFoundException.php":15984198,"lib\/Tools\/Exceptions\/ArrayNotFoundException.php":119469321,"lib\/Tools\/Exceptions\/RequestResultNotJsonException.php":1819604022,"lib\/Tools\/Exceptions\/SignatureException.php":4135972970,"lib\/Tools\/Exceptions\/InvalidItemException.php":2697814382,"lib\/Tools\/Exceptions\/WellKnownLinkNotFoundException.php":4159121169,"lib\/Tools\/Exceptions\/RequestNetworkException.php":453246520,"lib\/Tools\/Exceptions\/UnknownTypeException.php":3776373339,"lib\/Tools\/Exceptions\/DateTimeException.php":3819558445,"lib\/Tools\/Traits\/TNCSetup.php":2087128303,"lib\/Tools\/Traits\/TDeserialize.php":40344778,"lib\/Tools\/Traits\/TStringTools.php":195491532,"lib\/Tools\/Traits\/TConsoleTree.php":1953045507,"lib\/Tools\/Traits\/TArrayTools.php":107065102,"lib\/Tools\/Traits\/TAsync.php":2150747497,"lib\/Tools\/Traits\/TNCRequest.php":2685477491,"lib\/Tools\/Traits\/TNCWellKnown.php":682537172,"lib\/Tools\/Traits\/TNCLocalSignatory.php":1369452634,"lib\/Tools\/Traits\/TNCLogger.php":3438905615,"lib\/Tools\/Traits\/TNCSignatory.php":3204722111,"lib\/Tools\/IDeserializable.php":1840963260,"lib\/Tools\/ActivityPub\/NCSignature.php":3412759612,"lib\/Tools\/Model\/NCRequest.php":2836813437,"lib\/Tools\/Model\/NCRequestResult.php":4161785829,"lib\/Tools\/Model\/NCWebfinger.php":4043179298,"lib\/Tools\/Model\/NCSignatory.php":460204014,"lib\/Tools\/Model\/NCWellKnownLink.php":1203534144,"lib\/Tools\/Model\/SimpleDataStore.php":3794015914,"lib\/Tools\/Model\/Request.php":574047815,"lib\/Tools\/Model\/NCSignedRequest.php":3755998710,"lib\/Tools\/Model\/TreeNode.php":407985192,"lib\/IFederatedItemAsyncProcess.php":1768763470,"lib\/Events\/RequestingCircleMemberEvent.php":3995250,"lib\/Events\/AddingCircleMemberEvent.php":2383152349,"lib\/Events\/EditingCircleEvent.php":244866671,"lib\/Events\/MembershipsCreatedEvent.php":3448510229,"lib\/Events\/PreparingCircleMemberEvent.php":3019540765,"lib\/Events\/SharedItemsSyncRequestedEvent.php":1101995147,"lib\/Events\/CircleResultGenericEvent.php":1473683824,"lib\/Events\/CircleMemberGenericEvent.php":415119142,"lib\/Events\/CircleDestroyedEvent.php":3277551699,"lib\/Events\/CircleMemberEditedEvent.php":40903193,"lib\/Events\/CircleEditedEvent.php":3066634986,"lib\/Events\/CircleMemberRequestedEvent.php":1924785239,"lib\/Events\/DestroyingCircleEvent.php":3735477557,"lib\/Events\/MembershipsEditedEvent.php":2299609965,"lib\/Events\/MembershipsRemovedEvent.php":2651659751,"lib\/Events\/Files\/CreatingFileShareEvent.php":254806223,"lib\/Events\/Files\/FileShareCreatedEvent.php":1470935004,"lib\/Events\/Files\/PreparingFileShareEvent.php":2169101426,"lib\/Events\/CircleCreatedEvent.php":1117733505,"lib\/Events\/CircleGenericEvent.php":1559155969,"lib\/Events\/CreatingCircleEvent.php":2306768285,"lib\/Events\/CircleMemberRemovedEvent.php":133490551,"lib\/Events\/CircleMemberAddedEvent.php":2658217316,"lib\/Events\/RemovingCircleMemberEvent.php":3385682802,"lib\/Events\/EditingCircleMemberEvent.php":1543325352,"lib\/IQueryProbe.php":2865868626,"lib\/CirclesQueryHelper.php":2098331520,"lib\/IBroadcaster.php":2546838599,"lib\/IFederatedItemMemberEmpty.php":213782023,"lib\/Model\/GlobalScale\/GSShareMountpoint.php":3315247971,"lib\/Model\/GlobalScale\/GSEvent.php":137224992,"lib\/Model\/GlobalScale\/GSWrapper.php":2719296814,"lib\/Model\/GlobalScale\/GSShare.php":4200473692,"lib\/Model\/Federated\/EventWrapper.php":1467861897,"lib\/Model\/Federated\/FederatedEvent.php":3711061173,"lib\/Model\/Federated\/RemoteInstance.php":482160017,"lib\/Model\/Federated\/FederatedShare.php":2811421953,"lib\/Model\/SharesToken.php":2861357059,"lib\/Model\/Probes\/MemberProbe.php":3768197157,"lib\/Model\/Probes\/CircleProbe.php":339995689,"lib\/Model\/Probes\/BasicProbe.php":2973275655,"lib\/Model\/Member.php":1252239317,"lib\/Model\/Helpers\/MemberHelper.php":3324556941,"lib\/Model\/DavCard.php":2581584539,"lib\/Model\/SharingFrame.php":1594937260,"lib\/Model\/FederatedLink.php":1909955777,"lib\/Model\/Report.php":3444277527,"lib\/Model\/Circle.php":1299456529,"lib\/Model\/FileCacheWrapper.php":1035533403,"lib\/Model\/DeprecatedMember.php":2374518110,"lib\/Model\/Mountpoint.php":3948252563,"lib\/Model\/ShareToken.php":1946010418,"lib\/Model\/SearchResult.php":3551878101,"lib\/Model\/BaseCircle.php":32534729,"lib\/Model\/ModelManager.php":3164044928,"lib\/Model\/ManagedModel.php":1462064976,"lib\/Model\/ShareWrapper.php":683879466,"lib\/Model\/BaseMember.php":1026462325,"lib\/Model\/Mount.php":40054916,"lib\/Model\/FederatedUser.php":1206269253,"lib\/Model\/Membership.php":2863837345,"lib\/Model\/DeprecatedCircle.php":3434937094,"appinfo\/routes.php":2739162420,"lib\/Cron\/MaintenanceHeavy.php":806985314}} \ No newline at end of file diff --git a/appinfo/info.xml b/appinfo/info.xml index ac19d5fbf..632124894 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -66,7 +66,7 @@ Those groups of users (or "circles") can then be used by any other app for shari OCA\Circles\Command\MembersDetails OCA\Circles\Command\MembersLevel OCA\Circles\Command\MembersRemove - + OCA\Circles\Command\CirclesDebug diff --git a/appinfo/routes.php b/appinfo/routes.php index 9b4b6d21e..a8ac259c5 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -112,6 +112,12 @@ ['name' => 'Remote#members', 'url' => '/members/{circleId}/', 'verb' => 'GET'], ['name' => 'Remote#member', 'url' => '/member/{type}/{userId}/', 'verb' => 'GET'], ['name' => 'Remote#inherited', 'url' => '/inherited/{circleId}/', 'verb' => 'GET'], - ['name' => 'Remote#memberships', 'url' => '/memberships/{circleId}/', 'verb' => 'GET'] + ['name' => 'Remote#memberships', 'url' => '/memberships/{circleId}/', 'verb' => 'GET'], + + ['name' => 'Sync#getSyncedItem', 'url' => '/sync/item', 'verb' => 'GET'], +// ['name' => 'Remote#syncItem', 'url' => '/sync/item/{singleId}', 'verb' => 'GET'], + ['name' => 'Sync#syncShare', 'url' => '/sync/share', 'verb' => 'POST'], + ['name' => 'Debug#debugDaemon', 'url' => '/debug', 'verb' => 'POST'] + ] ]; diff --git a/drafts/federated_sync.md b/drafts/federated_sync.md new file mode 100644 index 000000000..1315bd4ca --- /dev/null +++ b/drafts/federated_sync.md @@ -0,0 +1,493 @@ +**Version 1.0.0 - 08/05/22 13:29** + +- comments on this version: + * it might not be necessary to have a random key string generated as `itemId`; `itemId` can be + auto-incremented, + * a use-case where data are de-sync between `Circles` and an app using this feature (ie. app failing + to fulfill the destruction of a remote share when requested) is fixed by adding a `deleted` + field/entry to `circles_item`. When an `item` is in the process of deletion, the entry related + to `itemId` in `circles_item` is flag as `deleted` and will only be deleted from the table when + the `IFederatedSyncManager` returns `ItemNotFoundException` on `serializeItem(itemId)`. No action + can be initiated on an `item` flag as `deleted` + +# Federated Sync + +The concept of **Federated Sync** is to provide enough tools for an app to share its own content over +multiple instances of Nextcloud. + +We call `item` a chunk of data identified by a unique id which represent an entry that can be shared. + +> If we take the Deck App as example, an `item` is a board with attached cards and comments. A user can +> create a board and share it. Recipients to the share have access to the board, cards and comments. + +The data of a shared `item` is copied in the database of every instances that host at least one `User` +whom is a member of the circles the `item` is shared to. + +To implements **Federated Sync**, the app must comply to some prerequisites: + +- Create a class that implements [`IFederatedSyncManager`](../lib/IFederatedSyncManager.php), +- Use [`CircleSharesManager`](../lib/ICircleSharesManager.php) to notify `Circles` when creating or + altering a share or an item. + +_Note:_ the current sync does not support `partial update`, which can be implemented in the future with +a `IFederatedPartialSyncManager` that will add few methods to the `IFederatedSyncManager`. + +### Known limits + +`Circles` allow the creating of circles over instances not necessarily available to each others as long +as the master instance of the circle (the instance the owner of the circle belongs to) can reach every +other instances. +However, sharing will require direct exchange with other instances from the instance the `item` have been +created. + +**A shared item will only be available between 2 instances if both instances are known to each other** ( +cf. `./occ circles:remote`) + +_In case of a circle grouping internal and external instances, the only solution will come from the +users: the shared item must be created on the same instance the owner of the circle belongs to._ + +# Implementing in an app + +The app need to register a _Federated Sync Manager_: + +``` +class Application extends App implements IBootstrap { + public function boot(IBootContext $context): void { + /** @var CirclesManager $circleManager */ + $circleManager = $context->getAppContainer()->get(CirclesManager::class); + $circleManager->getShareManager() + ->registerFederatedSyncManager(TestFederatedSync::class); + } +} +``` + +`TestFederatedSync` is a local class that implements `IFederatedSyncManager` which will be used +by `Circles` to communicate with the app + +### Full Support or Lazy Implementation ? + +As we will see, the concept of **Federated Sync** requires the app to register a `IFederatedSyncManager` +able to: + +- `syncItem(itemId, serializeData);` create/update item based on serializedData +- `serializeItem(itemId): array;` serialize an item based on itemId +- `deleteItem(itemId);` delete item based on itemId +- `isShareCreatable(itemId, circleId, extraData, membership): bool;` confirm a share can be generated by + this member +- `onShareCreation(itemId, circleId, extraData, membership)` create a new share +- `isShareModifiable(itemId, circleId, &extraData, membership)` confirm a share can be edited by this + member +- `onShareModification(itemId, circleId, extraData, membership)` update a share +- `isShareDeletable(itemId, circleId, extraData, membership): bool;` confirm a share can be deleted by + this member +- `onShareDeletion(itemId, circleId, memberships)` delete a share +- `isItemUpdatable(itemId, &serializedData, federatedUser): bool;` confirm an item is modifiable by this + user +- `updateItem(itemId, extraData, federatedUser)` + and the app to use `ICircleSharesManager` when: + +- a share is created using `createShare(itemId, circleId, extraData)` +- a share is updated using `updateShare(itemId, circleId, extraData)` +- a share is deleted using `deleteShare(itemId, circleId, extraData)` +- an item is updated using `updateItem(itemId, extraDataData)` +- an item is deleted using `deleteItem(itemId)` + +If is possible that the code used when doing most of those action might already exist in the external +app, and this code is called directly by the `Controller` as direct interaction with the front-end. + +We can assume that the code is structured as: + +- first, _verification of the feasibility of the action_, +- second, _proceed to the requested action_. + +When implementing **Federated Sync**, it is considered **FullSupport** to move all the code into the +generated `IFederatedSyncManager` and call the right methods from `ICircleSharesManager` at the right +time. Each process will run the same on every instance of the circle. + +The **LazyImplementation** is to keep the current code, and only notify `Circles` after the legacy code +of the app is done In that case, some method from `IFederatedSyncManager` related to the action to be +performed will not be run on the instance that initiate the action. + +> For a better understanding, and with the example of the Deck App, this is a quick overview of creating a new share +> In FullSupport: +> * user create a new share, +> * Deck's controller calls `createShare()` from `Circles` +> * `Circles` run `isShareCreatable()` +> * `Circles run `onShareCreation()` on every instance +> +> In LazyImplementation: +> * user create a new share, +> * Deck's controller confirm creation and fill the database or throw Exception if not possible +> * Deck calls `createShare()` from `Circles` +> * Circles run `isShareCreatable()` +> * Circles run `onShareCreation()` on every instance but the one that initiate the process + +While it is fully advice to use the **FullSupport**, both implementation should safely work on Single +Instance and GlobalScale. + +# Database, tables + +`circles_item`: + +- **id** +- **single_id** +- **instance** +- **app_id** +- **item_type** +- **item_id** +- **checksum** + +- `single_id` and `item_id` are each unique. +- `checksum` is a checksum of the current content of the shared item. It is used to compare version on + sync. +- `item_id` is `varchar(32)` and must be filled with a random string generated by the app. The app must + also store this `item_id` in the related table. + +`circles_share`: + +- **id** +- **single_id** +- **circle_id** + +- [`single_id`, `circle_id`] is a unique key pair + +`circles_lock`: + +- **id** +- **single_id** +- **update_type** +- **update_type_id** +- **time** + +- [`single_id`, `update_type`, `update_type_id`] is a unique key pair + +# Basic Knowledge about the Circles App + +quick reminder on the technology used by `Circles` that will be used in the process + +### IEntity and SingleId + +`Circles` allows to identify an entity from the instance by a _unique single id_, making sharing simpler +as the same table and code can be used for a share to a user or to a grouping of accounts. + +### Signed request + +When `Circles` from `instance1` is requesting `instance2`, the payload is signed using a private/public +key pairs, available through `/.well-known/webfinger`. Meaning that: + +- `instance2` can confirm the origin of the request as `instance1`, +- `instance1` can request a proof of ownership on the key pair when requesting `/.well-known/webfinger`. + +### IFederatedItem + +`IFederatedItem` is an existing process to exchange data related to a circle, making the master instance +of the circle (the one the owner of the circle belongs to) to be requested when running any operation on +a circle (example: add, edit, remove members). Once an operation is confirmed by master instance, every +other instances from the circle will be requested to run the exact same creation/modification process. + +This technology will be used by **Federated Sync** to broadcast some event to every instance of a circle. +However, the data itself will only be exchanged by direct request to the instance that host the +original `item` from each other instances. + +# Proof of concept, Analysis + +Draft of how **Federated Sync** should handle each sharing action while providing safe exchange of the +data: + +- `instanceX` describe the Circles App on Nextcloud number X, +- `userXY` is a user on Nextcloud number X, +- `circleX` is a circle owned by a user from Nextcloud number X, +- `appX` is the app on Nextcloud number X, + +In this draft, the step-by-step description of each process will be displayed in a table with 3 columns +that represent 3 different instances of Nextcloud named `Nextcloud 1`, `Nextcloud 2`,`Nextcloud 3`. The +flow of the process must be read from top to bottom. + +### New item, new share. + +This process describe: + +- the process of sharing a new item, +- the process of sharing an existing item already shared to another circle. +- the process of resharing a local item. + +Nextcloud 1 | Nextcloud 2 | Nextcloud 3 +---|---|--- +| | `user2` is owner of `circle2` | +| `user1` is member of `circle2` | | `user3` is member of `circle2` +| | +| `user1` share `item1` | +| `app1` calls `createShare(itemId, circleId, extraData): void;` | +| `instance1` verify `itemId` already exists in `circles_item`. If it does, compare with `appId`, `itemType`, extract `itemSingleId` and see if `instance` is local. (see `Action: Sharing a non-local item`) +| if `itemSingleId` is known, search for existing shares in `circles_share` based on `itemSingleId`, `circleId`. +| `instance1` get membership based on current session `FederatedUser`, `circleId` and request `app1` to verify share can be created using `isShareCreatable(itemId, circleId, extraData, Membership): bool;` +|`app1` confirms the share is creatable. +| if `itemSingleId` is not known, `instance1` generate a new one and created tne entry in `circles_item` using `itemSingleId`, `instance` (local), `appId`, `itemType`, `itemId` +| `instance1` creates an entry in `circles_share` using `itemSingleId` and `circleId` +| if `fullSupport`, `instance1` uses `onShareCreation(itemId, circleId, extraData, Membership): void;`and `app1` generate entries in its own shares table. +| `instance1` create a `IFederatedItem` using `circleId` containing `itemSingleId`, `appId`, `itemType`, `itemId` and request the master instance for `circle2` +| | +| _Async process at this point._ +| | +| | as master instance for `circle2`, `instance2` receive the `IFederatedItem`. +| | `instance2` verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`, `itemType`, `itemId` and confirm `instance`=`instance1`. +| | if `itemSingleId` is not known, create a new entry in `circles_item`. +| | `instance2` request all instances available in `circle2` and broadcast the `IFederatedItem` +| `instance1` will ignore the request | `instance2` will run the exact same process than `instance3` | `instance3` verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`, `itemType`, `itemId` and confirm `instance`=`instance1`. +| | | `instance3` send a signed request to `instance1` to retrieve content of the shared item, based on `itemSingleId`, `appId`, `itemType`, `itemId`, `circleId`. +| `instance1` confirms at least one user from `instance3` belongs to one of the circles `itemSingleId` is shared to using `circles_share` +| `instance1` returns serialized data of the item using `serializeItem(itemId)`, and its checksum. +| | | if `itemSingleId` was not known, and after confirmation from `instance1`, store data in `circles_item`. +| | | if `itemSingleId` was known, `instance3` compare `checksum`. If different to the one stored in `circles_item`, use `syncItem(itemId, serializedData): void;` and update `checksum` +| | | `app3` get serialized data and store it in its own table. +| | | `instance3` search for existing shares in `circles_share` based on `itemSingleId`, `circleId`. exit process if found. +| | | `instance3` store data in `circles_share` +| | | `instance3` communicate the new share to `app3` using `onShareCreation(itemId, circleId, extraData)` +| | | `app3` generate/update an entry in its own shares table + +### Sharing a non-local item + +This process describe: + +- the process of sharing a remote item, +- the process of sharing a local item + +We can assume that re-sharing is creating a share on an `item` that does not belong to the `initiator` of +the request. + +Nextcloud 1 | Nextcloud 2 | Nextcloud 3 +---|---|--- +| | `user2` is owner of `circle2` | +| `user1` is member of `circle2` | | `user3` is member of `circle2` +| | `user2` is owner of `circle2b` +| `user1` is member of `circle2b` | | `user3` is member of `circle2b` +| `user1` share `item1` to `circle2` with `permissions` +| | | `user3` share `item1` to `circle2b` +| | | `app3` calls `createShare(itemId, circleId, extraData): void;` +| | | `instance3` get `itemSingleId` from `circles_item`, based on `appId`, `itemType`, `itemId` see that `instance` is not local. (for local, see `Action: New item, new share`) +| | | `instance3` search for existing shares in `circles_share` based on `itemSingleId`, `circleId`. +| | | `instance3` request `instance1` about the new share using `itemSingleId`, `circleId`, `extraData`, `FederatedUser` (current session) +| `instance1` confirm `itemSingleId` exists in `circles_item` and `instance` is `instance1`. get `appId`, `itemType`, `itemId` +| `instance1` confirms `FederatedUser` is known and `instance` is `instance3` and belongs to one of the circle `itemSingleId` is shared to in `circles_share`. +| `instance1` get membership based on `FederatedUser`, `circleId` and request `app1` to verify share can be created using `isShareCreatable(itemId, circleId, extraData, Membership): bool;` +|`app1` confirms the share is creatable, based on other memberships of `initiator` that can be extract from `Membership` and its `FederatedUser` to verify permissions +| `instance1` creates an entry in `circles_share` using `itemSingleId` and `circleId` +| `instance1` uses `onShareCreation(itemId, circleId, extraData, Membership): void;` and `app1` generate entries in its own shares table. +| `instance1` create a `IFederatedItem` using `circleId` containing `itemSingleId`, `appId`, `itemType`, `itemId` and request the master instance for `circle2b` +| | +| _Async process at this point._ +| | | `instance1` confirmed the creation of the share and `instance3` will create an entry in `circles_share` and if no conflict run `onShareCreation(itemId, circleId, extraData)`. +| | +| | as master instance for `circle2b`, `instance2` receive the `IFederatedItem`. +| | `instance2` verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`, `itemType`, `itemId` and confirm `instance`=`instance1`. +| | if `itemSingleId` is not known, create a new entry in `circles_item`. +| | `instance2` request all instances available in `circle2b` and broadcast the `IFederatedItem` +| `instance1` will ignore the request | `instance2` verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`, `itemType`, `itemId` and confirm `instance`=`instance1`. | `instance3` will realise that share already exist in `circles_share` +| | `instance2` send a signed request to `instance1` to retrieve content of the shared item, based on `itemSingleId`, `appId`, `itemType`, `itemId`, `circleId`. +| `instance1` confirms at least one user from `instance3` belongs to one of the circles `itemSingleId` is shared to using `circles_share` +| `instance1` returns serialized data of the item using `serializeItem(itemId)`, and its checksum. +| | if `itemSingleId` was not known, and after confirmation from `instance1`, store data in `circles_item`. +| | if `itemSingleId` was known, `instance2` compare `checksum`. If different to the one stored in `circles_item`, use `syncItem(itemId, serializedData): void;` and update `checksum` +| | `app2` get serialized data and store it in its own table. +| | `instance2` search for existing shares in `circles_share` based on `itemSingleId`, `circleId`. exit process if found. +| | `instance2` store data in `circles_share` +| | `instance2` communicate the new share to `app2` using `onShareCreation(itemId, circleId, extraData)` +| | `app2` generate/update an entry in its own shares table + +### Edit shares permissions + +This process describe: + +- the process of update a local share, +- the process of update a remote share. + +Nextcloud 1 | Nextcloud 2 | Nextcloud 3 +---|---|--- +| | `user2` is owner of `circle2` | +| `user1` is member of `circle2` | | `user3` is member of `circle2` +| | +| `user1` share `item1` | +| | | `user3` update the share of `item1` to `circle2` +| | | `app3` uses `$circleManager->getShareManager(appId, itemType)->updateShare(itemId, circleId, extraData): void;` +| | | `instance3` get `itemSingleId` from `circles_item` and get remote host from `instance`. +| | | (in case the process was initiated from `Nextcloud1` the `instance would be local and the process goes directly to step `(b)`) +| | | `instance3` request `instance1` about the update using `itemSingleId`, `circleId`, `extraData`, `FederatedUser` (current session) +|`instance1` confirms `itemSingleId` exist in `circles_item` and `instance` is local +| `instance1` confirms at least one user from `instance3` belongs to one of the circle to which the item have been shared to using `circles_share` +|`instance1` confirms `FederatedUser` exist, is from `instance3` and belongs to one of the circle. +|`instance1` ask `app1` if share can be edited using `isShareModifiable(itemId, circleId, extraData, FederatedUser): bool;` +|`app1` confirm permission and rights based on the memberships of `FederatedUser`. +| `instance1` communicate the updated share to `app1` using `onShareModification(itemId, circleId, extraData)` +| `instance1` create a FederatedItem using `circleId` containing `shareSindleId`, `extraData` +| | +| _Async process at this point._ +| | | if update was initiated from `instance3`, `instance1` confirmed the update and `instance3` run `onShareModification(itemId, circleId, extraData)` +| | +| | as master instance for `circle2`, `instance2` receive the `IFederatedItem`. +| | `instance2` verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`, `itemType`, `itemId` and confirm `instance`=`instance1`. +| | if `itemSingleId` is not known, create a new entry in `circles_item`. +| | `instance2` request all instances available in `circle2` and broadcast the `IFederatedItem` +| `instance1` will ignore the request | `instance2` verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`, `itemType`, `itemId` and confirm `instance`=`instance1`. | if update was initiated from `instance3`, `instance3` will ignore the request. If not, will run exactly like `instance2` +| | `instance2` confirm the share exist in `circles_share`. +| | `instance2` use onShareModification(itemId, circleId, extraData) +| | `app2` update the share in its own table. + +### Updating an item + +This process describe: + +- updating a local item or one of its components, +- updating a non-local item or one of its components. + +**UpdateLock** + +To avoid race condition, `UpdateLock` allows the app to lock any further update on an item during a +previous update process. The app have the possibility to lock specific entry of the item. + +The `UpdateLock` will identify the locked part using `updateType` and `updateTypeId` + +> In case of the Deck App, it is possible to lock the action of moving a card (`updateType='card'`, `updateTypeId=cardId`) while not locking +> the edition of another card (`updateType='card'`, `updateTypeId=anotherCardId`) + +The `UpdateLock` also allow the app to enforce that the `item` (stored on the instance a user initiated +the update) is the last known version. + +Now, because most of the locks will only be kept few 1/10s, any parallel request will cycle for few +seconds, waiting for an available slot, before returning a lock error. +A `fifo` can be implemented in the future if needed. + +**Updating an item** + +Nextcloud 1 | Nextcloud 2 | Nextcloud 3 +---|---|--- +| `user1` is owner of `circle1` | +| | | `user3` is member of `circle1` +| | `user2` is owner of `circle2` +| `user1` is member of `circle2` +| | +| `user1` shares `item1` to `circle1` +| `user1` shares `item1` to `circle2` +| | | `user3` update `item1`. Based on the edit, `app3` generate an `updateLock` based on `updateType`, `updateTypeId` and if `checksum` needs to be up-to-date. +| | | `app3` calls `updateItem(itemId, extraData, updateLock): void;` +| | | `instance3` get `itemSingleId`, `checksum` from `circles_item` linked to `appId`, `itemType`, `itemId` and get remote host from `instance` +| | | `instance3` request `instance1` about the update using `itemSingleId`, `extraData`, `updateLock`, `FederatedUser` (current session), `checksum` +| `instance1` confirms `itemSingleId` exist and get `checksum` in `circles_item` and `instance` is local +| `instance1` confirms at least one user from `instance3` belongs to one of the circle to which the item have been shared to using `circles_share` +| `instance1` confirm `FederatedUser` exist in local database, is from `instance3` and belongs to one of the circle. +| `(a)` if `updateLock.verifyChecksum` is `true`, `instance1` confirm `checksum` from `circles_item` is identical to the one sent by `instance3` +| `instance1` search in `circles_lock` for a lock using `updateLock.updateType`, `updateLock.updateTypeId` +| if the `UpdateLock` is older than a minute, the entry is ignored and deleted. | if an `UpdateLock` exists, pause for a second. Retrieve `checksum` from `circles_item` and return to the previous step `(a)` +| `instance1` will wait for the `item` to `unlock` for few seconds and returns a SyncException if the lock is still up. +| `instance1` use `isItemUpdatable(itemId, extraData, federatedUser): bool;` +| `app1` confirm permissions to update based on `extraData`, `federatedUser`. +| Async process at this point with the confirmation (or not) that `app1` accepted the update. If accepted, the current `checksum` is also returned +| `instance1` generate an entry in `circles_lock` using `updateLock.updateType`, `updateLock.updateTypeId` and set `time` to now | | if `checksum` from `circles_item` is still the same and `updateLock.verifyChecksum=false`, or `checksum` is the one returned by `instance1`, then `instance3` initiate the update process locally using `onItemUpdate(itemId, extraData, federatedUser);` +| `instance1` initiate the updating process using `onItemUpdate(itemId, extraData, federatedUser);` | | `app3` update the item in its table. +| `app1` update the item in its table. | | `instance1` get serializedData from `app1` using `serializeItem(itemId)` and update `checksum` in `circles_item` +| `instance1` remove `UpdateLock` from `circles_lock` +| `instance1` get serializedData from `app1` using `serializeItem(itemId)` and update `checksum` in `circles_item` +| based on `circles_share`, `instance1` create one `IFederatedItem` per `circleId`, containing `itemSindleId`, `checksum`: +| _(need to verify if process can be run without a new async)_ +| `instance1` will manage `circle1` the same way `instance2` handle `circle2` | `instance2` get `itemId` from `circles_item` linked to `itemSingleId` in `circles_item` and confirm that `instance` is `instance1` and `circleId` is in `circles_share` +| | `instance2` broadcast the FederatedItem to all instances available in the circle +| `instance1` will exit process | | `instance2` will run the exact same process than `instance3` | `instance3` get `itemId` from linked to `itemSingleId` in `circles_item` and `circleId` from `circles_share` +| | | `instance3` verify `checksum` and if the same exit process | | | `instance3` send a signed request to `instance1` to retrieve content of the shared item, based on `itemSingleId` +| `instance1` confirms at least one user from `instance3` belongs to one of the circle to which the item have been shared to using `circles_share` +| `instance1` get serialized data of the item using `serializeItem(itemId): array;` +| `app1` returns serialized data based on `itemId`. +| `instance1` generate a `checksum`, update the one stored in `circles_item` if needed, and returns `serializedData` and `checksum` +| | | `instance3` compare `checksum` with the one in `circles_item`. If different, run `syncItem(itemId, serializedData)`; +| | | `app3` update the item in its table. + +### Delete share + +not documented yet but will work like `Edit shares permissions` + +### Remove item + +not documented yet, but will work more or less like `Update Item` + +### temp + +[comment]: <> (| `instance1` communicate the updated item to `app1`) + +[comment]: <> (using `IFederatedSyncManager::syncItem(itemId, serializeData)`) + +[comment]: <> (-------------------------) + +[comment]: <> (------------------------------) + +[comment]: <> (| `instance1` verify `itemId` already exists in `circles_item`. If it does, compare with `appId`) + +[comment]: <> (, `itemType`, extract `itemSingleId` and see if `instance` is local. () + +[comment]: <> (see `Action: Resharing a non-local item`)) + +[comment]: <> (| if `itemSingleId` is known, search for existing shares in `circles_share` based on `itemSingleId`) + +[comment]: <> (, `circleId`. | `instance1` get membership based on current session `FederatedUser`, `circleId` and) + +[comment]: <> (request `app1` to verify share can be created) + +[comment]: <> (using `isShareCreatable(itemId, circleId, extraData, Membership): bool;`) + +[comment]: <> (|`app1` confirms the share is creatable. | if `itemSingleId` is not known, `instance1` generate a new one) + +[comment]: <> (and created tne entry in `circles_item` using `itemSingleId`, `instance` (local), `appId`, `itemType`) + +[comment]: <> (, `itemId`) + +[comment]: <> (| `instance1` creates an entry in `circles_share` using `itemSingleId` and `circleId`) + +[comment]: <> (| if `fullSupport`, `instance1` uses `onShareCreation(itemId, circleId, extraData, Membership): void;`) + +[comment]: <> (and `app1` generate entries in its own shares table. | `instance1` create a `IFederatedItem`) + +[comment]: <> (using `circleId` containing `itemSingleId`, `appId`, `itemType`, `itemId` and request the master instance) + +[comment]: <> (for `circle2`) + +[comment]: <> (| | | _Async process at this point._) + +[comment]: <> (| | | | as master instance for `circle2`, `instance2` receive the `IFederatedItem`. | | `instance2`) + +[comment]: <> (verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`, `itemType`, `itemId`) + +[comment]: <> (and confirm `instance`=`instance1`. | | if `itemSingleId` is not known, create a new entry) + +[comment]: <> (in `circles_item`. | | `instance2` request **all instances** available in `circle2` to send and broadcast) + +[comment]: <> (the `IFederatedItem`) + +[comment]: <> (| `instance1` will ignore the request | `instance2` will run the exact same process than `instance3`) + +[comment]: <> (| `instance3` verify `itemSingleId` exists in `circles_item`. If it does, compare with `appId`) + +[comment]: <> (, `itemType`, `itemId` and confirm `instance`=`instance1`. | | | `instance3` send a signed request) + +[comment]: <> (to `instance1` to retrieve content of the shared item, based on `itemSingleId`, `appId`, `itemType`) + +[comment]: <> (, `itemId`, `circleId`. | `instance1` confirms at least one user from `instance3` belongs to one of the) + +[comment]: <> (circles `itemSingleId` is shared to using `circles_share`) + +[comment]: <> (| `instance1` returns serialized data of the item using `serializeItem(itemId)`, and its checksum. | | |) + +[comment]: <> (if `itemSingleId` was not known, and after confirmation from `instance1`, store data in `circles_item`. |) + +[comment]: <> (| | if `itemSingleId` was known, `instance3` compare `checksum`. If different to the one stored) + +[comment]: <> (in `circles_item`, use `syncItem(itemId, serializedData): void;` and update `checksum`) + +[comment]: <> (| | | `app3` get serialized data and store it in its own table. | | | `instance3` search for existing) + +[comment]: <> (shares in `circles_share` based on `itemSingleId`, `circleId`. exit process if found. | | | `instance3`) + +[comment]: <> (store data in `circles_share`) + +[comment]: <> (| | | `instance3` communicate the new share to `app3`) + +[comment]: <> (using `onShareCreation(itemId, circleId, extraData)`) + +[comment]: <> (| | | `app3` generate/update an entry in its own shares table) + diff --git a/lib/CircleSharesManager.php b/lib/CircleSharesManager.php new file mode 100644 index 000000000..4a09d28cb --- /dev/null +++ b/lib/CircleSharesManager.php @@ -0,0 +1,243 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles; + +use Exception; +use OCA\Circles\Exceptions\CircleSharesManagerException; +use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Service\CircleService; +use OCA\Circles\Service\ConfigService; +use OCA\Circles\Service\DebugService; +use OCA\Circles\Service\FederatedSyncItemService; +use OCA\Circles\Service\FederatedSyncService; +use OCA\Circles\Service\FederatedSyncShareService; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; + +/** + * Class CircleSharesManager + * + * @package OCA\Circles + */ +class CircleSharesManager implements ICircleSharesManager { + + + private CircleService $circleService; + private FederatedSyncService $federatedSyncService; + private FederatedSyncItemService $federatedSyncItemService; + private FederatedSyncShareService $federatedSyncShareService; + private ConfigService $configService; + private DebugService $debugService; + + private string $originAppId = ''; + private string $originItemType = ''; + + + /** + * @param CircleService $circleService + * @param FederatedSyncItemService $federatedSyncItemService + * @param FederatedSyncShareService $federatedSyncShareService + * @param ConfigService $configService + */ + public function __construct( + CircleService $circleService, + FederatedSyncService $federatedSyncService, + FederatedSyncItemService $federatedSyncItemService, + FederatedSyncShareService $federatedSyncShareService, + ConfigService $configService, + DebugService $debugService + ) { + $this->circleService = $circleService; + $this->federatedSyncService = $federatedSyncService; + $this->federatedSyncItemService = $federatedSyncItemService; + $this->federatedSyncShareService = $federatedSyncShareService; + $this->configService = $configService; + $this->debugService = $debugService; + } + + + /** + * @param string $syncManager + * + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface + */ + public function registerFederatedSyncManager(string $syncManager): void { + if ($this->originAppId !== '' || $this->originItemType !== '') { + return; + } + + $federatedSyncManager = \OC::$server->get($syncManager); + if (!($federatedSyncManager instanceof IFederatedSyncManager)) { + // log something + return; + } + + $this->federatedSyncService->addFederatedSyncManager($federatedSyncManager); + } + + + /** + * @param string $itemId + * @param string $circleId + * @param array $extraData + * + * @throws CircleSharesManagerException + * @throws Exceptions\CircleNotFoundException + * @throws Exceptions\FederatedSyncConflictException + * @throws Exceptions\FederatedSyncManagerNotFoundException + * @throws Exceptions\InitiatorNotFoundException + * @throws Exceptions\RequestBuilderException + * @throws Exceptions\SyncedSharedAlreadyExistException + */ + public function createShare( + string $itemId, + string $circleId, + array $extraData = [] + ): void { + $this->debugService->setDebugType('federated_sync'); + $this->debugService->info('{~New request to create a SyncedShare} based on {appId}.{itemType}.{itemId}', $circleId, [ + 'appId' => $this->originAppId, + 'itemType' => $this->originItemType, + 'itemId' => $itemId, + 'extraData' => $extraData + ]); + + try { + $this->mustHaveOrigin(); + + // TODO: verify rules that apply when sharing to a circle + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->mustBeMember(); + + $circle = $this->circleService->getCircle($circleId, $probe); + + // get valid SyncedItem based on appId, itemType, itemId + $syncedItem = $this->federatedSyncItemService->getSyncedItem( + $this->originAppId, + $this->originItemType, + $itemId + ); + + $this->debugService->info( + 'initiating the process of sharing {syncedItem.singleId} to {circle.id}', + $circleId, [ + 'circle' => $circle, + 'syncedItem' => $syncedItem, + 'extraData' => $extraData, + 'isLocal' => $syncedItem->isLocal() + ] + ); + + // confirm item is local + if (!$syncedItem->isLocal()) { + // TODO: sharing a remote item + return; + } + + $this->federatedSyncShareService->createShare($syncedItem, $circle, $extraData); + } catch (Exception $e) { + $this->debugService->exception($e, $circleId); + throw $e; + } +// this->$this->federatedItemService->getSharedItem + } + + /** + * @param string $itemId + * @param string $circleId + * @param array $extraData + * + * @throws CircleSharesManagerException + */ + public function updateShare( + string $itemId, + string $circleId, + array $extraData = [] + ): void { + $this->mustHaveOrigin(); + } + + /** + * @param string $itemId + * @param string $circleId + * + * @throws CircleSharesManagerException + */ + public function deleteShare(string $itemId, string $circleId): void { + $this->mustHaveOrigin(); + } + + /** + * @param string $itemId + * @param array $serializedData + */ + public function updateItem( + string $itemId, + array $serializedData + ): void { + $this->mustHaveOrigin(); + } + + /** + * @param string $itemId + * + * @throws CircleSharesManagerException + */ + public function deleteItem(string $itemId): void { + $this->mustHaveOrigin(); + } + + + /** + * @param string $appId + * @param string $itemType + */ + public function setOrigin(string $appId, string $itemType) { + $this->originAppId = $appId; + $this->originItemType = $itemType; + } + + /** + * @throws CircleSharesManagerException + */ + private function mustHaveOrigin(): void { + if ($this->originAppId !== '' && $this->originItemType !== '') { + return; + } + + throw new CircleSharesManagerException( + 'ICirclesManager::getShareManager(appId, itemType) used empty params' + ); + } +} diff --git a/lib/CirclesManager.php b/lib/CirclesManager.php index 32da68c60..e375dd8c1 100644 --- a/lib/CirclesManager.php +++ b/lib/CirclesManager.php @@ -64,36 +64,22 @@ use OCA\Circles\Service\MembershipService; use OCA\Circles\Tools\Exceptions\InvalidItemException; -/** - * Class CirclesManager - * - * @package OCA\Circles - */ -class CirclesManager { - - /** @var FederatedUserService */ - private $federatedUserService; - - /** @var CircleService */ - private $circleService; - - /** @var MemberService */ - private $memberService; - - /** @var MembershipService */ - private $membershipService; - - /** @var ConfigService */ - private $configService; +class CirclesManager { - /** @var CirclesQueryHelper */ - private $circlesQueryHelper; + private CircleSharesManager $circleSharesManager; + private FederatedUserService $federatedUserService; + private CircleService $circleService; + private MemberService $memberService; + private MembershipService $membershipService; + private ConfigService $configService; + private CirclesQueryHelper $circlesQueryHelper; /** * CirclesManager constructor. * + * @param CircleSharesManager $circleSharesManager * @param FederatedUserService $federatedUserService * @param CircleService $circleService * @param MemberService $memberService @@ -102,6 +88,7 @@ class CirclesManager { * @param CirclesQueryHelper $circlesQueryHelper */ public function __construct( + CircleSharesManager $circleSharesManager, FederatedUserService $federatedUserService, CircleService $circleService, MemberService $memberService, @@ -109,6 +96,7 @@ public function __construct( ConfigService $configService, CirclesQueryHelper $circlesQueryHelper ) { + $this->circleSharesManager = $circleSharesManager; $this->federatedUserService = $federatedUserService; $this->circleService = $circleService; $this->memberService = $memberService; @@ -118,6 +106,24 @@ public function __construct( } + /** + * @param string $appId + * @param string $itemType + * + * @return CircleSharesManager + */ + public function getShareManager(string $appId = '', string $itemType = ''): ICircleSharesManager { + if ($appId === '') { + return $this->circleSharesManager; + } + + $clone = clone $this->circleSharesManager; + $clone->setOrigin($appId, $itemType); + + return $clone; + } + + /** * @param string $federatedId * @param int $type diff --git a/lib/CirclesQueryHelper.php b/lib/CirclesQueryHelper.php index 5dbf0cd43..2220d8409 100644 --- a/lib/CirclesQueryHelper.php +++ b/lib/CirclesQueryHelper.php @@ -86,17 +86,15 @@ public function getQueryBuilder(): IQueryBuilder { /** - * @param string $alias - * @param string $field + * @param array $fields * @param bool $fullDetails * * @return ICompositeExpression - * @throws RequestBuilderException * @throws FederatedUserNotFoundException + * @throws RequestBuilderException */ public function limitToSession( - string $alias, - string $field, + array $fields, bool $fullDetails = false ): ICompositeExpression { $session = $this->federatedUserService->getCurrentUser(); @@ -104,7 +102,7 @@ public function limitToSession( throw new FederatedUserNotFoundException('session not initiated'); } - $this->queryBuilder->setDefaultSelectAlias($alias); +// $this->queryBuilder->setDefaultSelectAlias($alias); $this->queryBuilder->setOptions( [CoreQueryBuilder::HELPER], [ @@ -116,8 +114,8 @@ public function limitToSession( return $this->queryBuilder->limitToInitiator( CoreQueryBuilder::HELPER, $session, - $field, - $alias + '', + $fields ); } @@ -127,17 +125,18 @@ public function limitToSession( * @param string $field * @param IFederatedUser $federatedUser * @param bool $fullDetails + * @param array $extraFields * * @return ICompositeExpression * @throws RequestBuilderException */ public function limitToInheritedMembers( - string $alias, string $field, + string $alias, IFederatedUser $federatedUser, - bool $fullDetails = false + bool $fullDetails = false, + array $extraFields = [] ): ICompositeExpression { - $this->queryBuilder->setDefaultSelectAlias($alias); $this->queryBuilder->setOptions( [CoreQueryBuilder::HELPER], [ @@ -150,7 +149,8 @@ public function limitToInheritedMembers( CoreQueryBuilder::HELPER, $federatedUser, $field, - $alias + $alias, + $extraFields ); } diff --git a/lib/Command/CirclesDebug.php b/lib/Command/CirclesDebug.php new file mode 100644 index 000000000..355d21cca --- /dev/null +++ b/lib/Command/CirclesDebug.php @@ -0,0 +1,917 @@ + + * @copyright 2017 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Command; + +use Exception; +use JetBrains\PhpStorm\Pure; +use OC\Core\Command\Base; +use OCA\Circles\Model\Debug; +use OCA\Circles\Service\ConfigService; +use OCA\Circles\Service\DebugService; +use OCA\Circles\Tools\Model\ReferencedDataStore; +use OCA\Circles\Tools\Traits\TArrayTools; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Terminal; + +/** + * Class CirclesCheck + * + * @package OCA\Circles\Command + */ +class CirclesDebug extends Base { + use TArrayTools; + + public const REFRESH = 50000; + + private DebugService $debugService; + private ConfigService $configService; + + private TopPanel $topPanel; + private BottomLeftPanel $bottomLeftPanel; + private BottomRightPanel $bottomRightPanel; + private ProgressBar $display; + + /** @var Panel[] $panels */ + private array $panels = []; + /** @var Debug[] $debugs */ + private array $debugs = []; + private bool $refresh = false; + private int $lastId = 0; + + /** + * @param DebugService $debugService + */ + public function __construct(DebugService $debugService, ConfigService $configService) { + parent::__construct(); + + $this->debugService = $debugService; + $this->configService = $configService; + } + + protected function configure() { + parent::configure(); + $this->setName('circles:debug') + ->setDescription('Debug!') + ->addOption('circle', '', InputOption::VALUE_REQUIRED, 'filter circle', '') + ->addOption('history', '', InputOption::VALUE_REQUIRED, 'last history', '50') + ->addOption('size', '', InputOption::VALUE_REQUIRED, 'height', '0') + ->addOption('ping', '', InputOption::VALUE_NONE, 'ping debug daemon') + ->addOption('instance', '', InputOption::VALUE_REQUIRED, 'filter instance', ''); + } + + /** + * @param InputInterface $input + * @param OutputInterface $output + * + * @return int + * @throws Exception + */ + protected function execute(InputInterface $input, OutputInterface $output): int { + if ($input->getOption('ping')) { + $this->debugService->info('ping.'); + + return 0; + } + + $this->init(); + $this->initTerminal((int)$input->getOption('size')); + $this->initPanel($output); + $this->initHistory((int)$input->getOption('history')); + + while (true) { + try { + $this->keyPressed(); + } catch (QuitException $e) { + break; + } + + $this->live(); + $this->refresh(); + + usleep(self::REFRESH); + } + +// $this->displayDebugs($debugs); + + return 0; + } + + + private function init(): void { + stream_set_blocking(STDIN, false); + readline_callback_handler_install( + '', + function () { + } + ); + + $this->panels[] = $this->topPanel = new TopPanel( + [ + 'currentLine' => 'topPanelCurrentLine', + ] + ); + $this->panels[] = $this->bottomLeftPanel = new BottomLeftPanel( + [ + 'currentLine' => 'bottomLeftPanelCurrentLine', + ] + ); + $this->panels[] = $this->bottomRightPanel = new BottomRightPanel( + [ + 'currentLine' => 'bottomRightPanelCurrentLine', + ] + ); + } + + + /** + * @param int $height + */ + private function initTerminal(int $height = 0): void { + if ($height === 0) { + $height = (new Terminal())->getHeight() - 1; + } + + $this->topPanel->setHeight((int)floor($height / 2)); + $this->bottomLeftPanel->setHeight($height - $this->topPanel->getHeight()); + $this->bottomRightPanel->setHeight($height - $this->topPanel->getHeight()); + + $this->topPanel->setMaxLines($this->topPanel->getHeight() - 2); + $this->bottomLeftPanel->setMaxLines($this->bottomLeftPanel->getHeight() - 7); + $this->bottomRightPanel->setMaxLines($this->bottomRightPanel->getHeight() - 2); + } + + + /** + * @param OutputInterface $output + */ + private function initPanel(OutputInterface $output): void { + $this->display = new ProgressBar($output); + $this->initPanelMessage(); + $this->display->setOverwrite(true); + + $lines = []; + $lines[] = '┌─%top%──────────────────────────────────────────────────────'; + + for ($i = 0; $i < $this->topPanel->getMaxLines(); $i++) { + $lines[] = '│' + . $this->incrementString($i, 'topPanelCurrentLine', '%') + . $this->incrementstring($i, 'lineT', '%'); + + $this->update($this->incrementString($i, 'topPanelCurrentLine'), ' '); + $this->update($this->incrementString($i, 'lineT'), ' '); + } + + $lines[] = '└─────'; + $lines[] = + '┌────────────────────────────────────────────┬─────────────%test%─────────────────────────'; + + for ($i = 0; $i < $this->bottomLeftPanel->getMaxLines(); $i++) { + $lines[] = '│' + . $this->incrementString($i, 'bottomLeftPanelCurrentLine', '%') . ' ' + . $this->incrementString($i, 'lineBL', ':42s%') . ' ' + . '│ ' + . $this->incrementString($i, 'lineBR', '%'); + + $this->update($this->incrementString($i, 'bottomLeftPanelCurrentLine'), ''); + $this->update($this->incrementString($i, 'lineBL'), ''); + $this->update($this->incrementString($i, 'lineBR'), ''); + } + + $more = [' Thread', ' Type', 'CircleId', 'Instance', ' Time']; + for ($j = 0; $j < count($more); $j++) { + $lines[] = '│ ' . strtolower($more[$j]) . ': %curr' + . trim($more[$j]) . ':-32s% │ ' + . $this->incrementString($i + $j, 'lineBR', '%'); + $this->update($this->incrementString($i + $j, 'lineBR'), ''); + } + $lines[] = '└────────────────────────────────────────────┘'; + + $this->setCurr(); + +// $this->display->clear(); + $this->display->setFormat(implode("\n", $lines) . "\n"); + $this->display->start(); + } + + + /** + * @param int $history + */ + private function initHistory(int $history): void { + $debugs = $this->debugService->getHistory(max($history, 1)); + $this->lastId = empty($debugs) ? 0 : $debugs[0]->getId(); + + if ($history < 1) { + return; + } + + $this->debugs = array_reverse($debugs, false); + $this->topPanel->setCurrentPage(max(count($this->debugs) - 3, 0)); + + $this->refreshHistory(); + } + + /** + * + */ + private function live(): void { + $debugs = $this->debugService->getSince($this->lastId); + if (empty($debugs)) { + return; + } + + $this->lastId = $debugs[0]->getId(); + + foreach (array_reverse($debugs, false) as $debug) { + $this->debugs[] = $debug; + } + + $this->refreshHistory(); + } + + + private function refreshHistory(): void { + $selectableLines = 0; + for ($i = 0; $i < $this->topPanel->getMaxLines(); $i++) { + $k = $this->topPanel->getCurrentPage() + $i; + if (!array_key_exists($k, $this->debugs)) { + $this->update($this->incrementString($i, 'lineT'), ''); + } else { + $item = $this->debugs[$k]; + $debug = $item->getDebug(); + + $instance = ($this->configService->isLocalInstance($item->getInstance())) ? + 'local' : $item->getInstance(); + + $instanceColor = $this->configService->getAppValue('debug_instance.' . $instance); + if ($instanceColor === '') { + $instanceColor = 'white'; + } + + $line = '' . $instance . ' - '; + $action = $debug->g(DebugService::ACTION); + + preg_match_all('/{((?:[^{}]*|(?R))*)}/x', $action, $match); + foreach ($match[1] as $entry) { + $flag = substr($entry, 0, 1); + if ($flag === '!') { + $path = substr($entry, 1); + $color = 'fg=yellow'; + } else if ($flag === '?') { + $path = substr($entry, 1); + $color = 'fg=red'; + } else if ($flag === '~') { + $path = substr($entry, 1); + $color = 'fg=cyan'; + } else if ($flag === '`') { + $path = substr($entry, 1); + $color = 'options=reverse'; + } else { + $path = $entry; + $color = 'fg=green'; + } + + $value = $this->get($path, $debug->jsonSerialize()); + if ($value === '') { + $value = $path; + } + + $action = str_replace( + '{' . $entry . '}', + '<' . $color . '>' . $value . '', + $action + ); + } + + $selectableLines++; + + $line .= $action; + $this->update($this->incrementString($i, 'lineT'), $line); + } + } + + $this->topPanel->setSelectableLines($selectableLines); + } + + /** + * + */ + private function initPanelMessage(): void { + $this->updates([ + 'test' => '', + ]); + } + + + /** + * @param array $data + */ + private function updates(array $data): void { + foreach ($data as $k => $v) { + $this->update($k, (string)$v); + } + } + + /** + * @param string $key + * @param string $value + */ + private function update(string $key, string $value = ''): void { + $this->display->setMessage($value, $key); + $this->forceRefresh(); + } + + + /** + * @throws QuitException + */ + public function keyPressed(): void { + $n = fread(STDIN, 16); + if ($n !== '') { + if (substr($n, 1, 1) === '[') { + $this->keyActionTopPanel(strtolower(substr($n, 2, 1))); + } + + $c = str_split($n, 1); + foreach ($c as $a) { + $this->onKeyPressed(strtolower($a)); + } + } + } + + /** + * @param string $key + * + * @throws QuitException + */ + public function onKeyPressed(string $key): void { + switch ($key) { + case 'q': + throw new QuitException(); + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + $this->keyActionLeftPanel((int)$key); + break; + + case 'w': + case 's': + case 'a': + case 'd': + $this->keyActionBottomRightPanel($key); + break; + + default: + return; + } + } + + + /** + * + */ + private function forceRefresh(): void { + $this->refresh = true; + } + + /** + * + */ + private function refresh(): void { + if (!$this->isRefreshNeeded()) { + return; + } + + $this->display->display(); + $this->cleanRefresh(); + } + + /** + * @return bool + */ + #[Pure] + private function isRefreshNeeded(): bool { + if ($this->refresh) { + return true; + } + + foreach ($this->panels as $panel) { + if ($panel->isModified()) { + return true; + } + } + + return false; + } + + private function cleanRefresh(): void { + $this->refresh = false; + foreach ($this->panels as $panel) { + $panel->setModified(false); + } + } + + + /** + * @return Debug + */ + #[Pure] + private function getSelectedEntry(): Debug { + return $this->debugs[$this->topPanel->getCurrentPage() + $this->topPanel->getCurrentLine()]; + } + + + /** + * @param string $key + */ + public function keyActionTopPanel(string $key): void { + switch ($key) { + case 'a': + $done = $this->topPanel->keyUp(); + break; + case 'b': + $done = $this->topPanel->keyDown(); + break; + case 'c': + $done = $this->topPanel->keyRight(); + $this->refreshHistory(); + break; + case 'd': + $done = $this->topPanel->keyLeft(); + $this->refreshHistory(); + break; + + default: + return; + } + + if ($done) { + $this->displayTopPanelCurrentLine(); + $this->displayBottomLeftPanelItems(); + + $this->bottomRightPanel->setLines([]); + $this->bottomRightPanel->setSelectableLines(count($this->bottomRightPanel->getLines())); + $this->displayBottomRightPanelItems(); + } + } + + /** + * @param string $key + */ + public function keyActionBottomRightPanel(string $key): void { + switch ($key) { + case 'w': + $this->bottomRightPanel->keyUp(); + break; + case 's': + $this->bottomRightPanel->keyDown(); + break; +// case 'a': +// $this->bottomRightPanel->keyLeft(); +// break; +// case 'd': +// $this->bottomRightPanel->keyRight(); +// break; + + default: + return; + } + + $this->displayBottomRightPanelItems(); + } + + /** + * + */ + private function displayTopPanelCurrentLine(): void { + for ($i = 0; $i < $this->topPanel->getMaxLines(); $i++) { + if ($this->topPanel->getCurrentLine() === $i) { + $this->update( + $this->incrementString($i, $this->get('currentLine', $this->topPanel->getInternal())), +// '·' + '>' + ); + } else { + $this->update( + $this->incrementString($i, $this->get('currentLine', $this->topPanel->getInternal())), + ' ' + ); + } + } + } + + + /** + * + */ + private function displayBottomLeftPanelItems(): void { + $this->setCurr($this->getSelectedEntry()); + $debug = $this->getSelectedEntry()->getDebug(); + + + $references = $debug->getAllReferences(); + + $items = []; + $this->bottomLeftPanel->setSelectableLines(count($references)); + for ($i = 0; $i < $this->bottomLeftPanel->getMaxLines(); $i++) { + $entry = array_shift($references); + if (is_null($entry)) { + $this->update($this->incrementString($i, 'lineBL'), ''); + } else { + $items[] = $name = $this->get(ReferencedDataStore::KEY_NAME, $entry); + + $type = $this->get(ReferencedDataStore::KEY_TYPE, $entry); + if ($type === ReferencedDataStore::OBJECT) { + $path = $this->get(ReferencedDataStore::KEY_CLASS, $entry); + $type = implode('\\', array_slice(explode('\\', $path), -2)); + } + + $this->update( + $this->incrementString($i, 'lineBL'), + ($i + 1) . '. ' . $name . ' (' . $type . ')' + ); + } + } + + $this->bottomLeftPanel->setItems($items); + $this->bottomLeftPanel->setCurrentLine(-1); + + $this->displayBottomLeftPanelCurrentLine(); + } + + + private function displayBottomLeftPanelCurrentLine(): void { + for ($i = 0; $i < $this->bottomLeftPanel->getMaxLines(); $i++) { + if ($this->bottomLeftPanel->getCurrentLine() === $i) { + $this->update( + $this->incrementString( + $i, + $this->get('currentLine', $this->bottomLeftPanel->getInternal()) + ), + '' + ); + } else { + $this->update( + $this->incrementString( + $i, + $this->get('currentLine', $this->bottomLeftPanel->getInternal()) + ), + '' + ); + } + } + } + + + private function displayBottomRightPanelItems(): void { + + $this->update($this->incrementString(0, 'lineBR')); +// $this->bottomLeftPanel->setSelectableLines(count($references)); + + $lines = $this->bottomRightPanel->getLines(); + for ($i = 0; $i < $this->bottomRightPanel->getMaxLines(); $i++) { + $c = $i + $this->bottomRightPanel->getCurrentLine(); + if ($this->bottomRightPanel->getSelectableLines() < $c || empty($lines)) { + $this->update($this->incrementString($i, 'lineBR'), ''); + } else { + $this->update($this->incrementString($i, 'lineBR'), (string)$lines[$c]); + } +// $type = $this->get(ReferencedDataStore::KEY_TYPE, $entry); +// if ($type === ReferencedDataStore::OBJECT) { +// $path = $this->get(ReferencedDataStore::KEY_CLASS, $entry); +// $type = implode('\\', array_slice(explode('\\', $path), -2)); +// } +// +// $this->update( +// $this->incrementString($i, 'lineBL'), +// 'circle (' . $type . ')' +// ); + } + + } + + + public function test(int $b) { + $this->update('top', (string)$b); + } + + + private function keyActionLeftPanel(int $item): void { + $this->bottomLeftPanel->onKeyItem($item); + + $this->displayBottomLeftPanelCurrentLine(); + + + $items = $this->bottomLeftPanel->getItems(); + $debug = $this->getSelectedEntry()->getDebug(); + + if ($this->bottomLeftPanel->getCurrentLine() < count($items)) { + $this->bottomRightPanel->setLines( + explode( + "\n", + trim( + json_encode( + $debug->gAll()[$items[$this->bottomLeftPanel->getCurrentLine()]], + JSON_PRETTY_PRINT + ) + ) + ) + ); + } + $this->bottomRightPanel->setSelectableLines(count($this->bottomRightPanel->getLines())); + $this->bottomRightPanel->setCurrentLine(0); + + $this->displayBottomRightPanelItems(); + } + + + private function incrementString(int $number, string $prefix = '', string $wrapper = ''): string { + $str = sprintf('%03d', $number); + $chars = 'ABCDEFGHIJ'; + $result = ''; + for ($i = 0; $i < 3; $i++) { + $result .= $chars[(int)$str[$i]]; + } + + if ($wrapper !== '') { + $prefix = '%' . $prefix; + } + + return $prefix . $result . $wrapper; + } + + private function setCurr(?Debug $debug = null) { + if (is_null($debug)) { + $this->update('currThread', ''); + $this->update('currType', ''); + $this->update('currCircleId', ''); + $this->update('currInstance', ''); + $this->update('currTime', ''); + + return; + } + + $this->update('currThread', $debug->getThread() ?? ''); + $this->update('currType', $debug->getType() ?? ''); + $this->update('currCircleId', $debug->getCircleId() ?? ''); + $this->update('currInstance', $debug->getInstance() ?? ''); + $this->update('currTime', (string)$debug->getTime() ?? ''); + } + +} + + +class Panel { + private array $lines = []; + private int $maxLines = 0; + private int $selectableLines = 0; + private int $currentLine = -1; + private int $height = 0; + private bool $modified = true; + private array $internal; + private int $currentPage; + + public function __construct(array $internal = []) { + $this->internal = $internal; + } + + /** + * @param array $lines + */ + public function setLines(array $lines): void { + $this->lines = $lines; + } + + /** + * @param int $page + * + * @return array + */ + public function getLines(int $page = -1): array { + return $this->lines; + } + + + /** + * @param int $maxLines + */ + public function setMaxLines(int $maxLines): void { + $this->maxLines = $maxLines; + } + + /** + * @return int + */ + public function getMaxLines(): int { + return $this->maxLines; + } + + /** + * @param int $selectableLines + */ + public function setSelectableLines(int $selectableLines): void { + $this->selectableLines = $selectableLines; + } + + /** + * @return int + */ + public function getSelectableLines(): int { + return $this->selectableLines; + } + + + /** + * @param int $currentLine + */ + public function setCurrentLine(int $currentLine): void { + if ($this->currentLine !== $currentLine) { + $this->setModified(true); + } + + $this->currentLine = $currentLine; + } + + /** + * @return int + */ + public function getCurrentLine(): int { + return $this->currentLine; + } + + + /** + * @param int $currentPage + */ + public function setCurrentPage(int $currentPage): void { + $this->currentPage = $currentPage; + } + + /** + * @return int + */ + public function getCurrentPage(): int { + return $this->currentPage; + } + + /** + * @param int $height + */ + public function setHeight(int $height): void { + $this->height = $height; + } + + /** + * @return int + */ + public function getHeight(): int { + return $this->height; + } + + /** + * @return array + */ + public function getInternal(): array { + return $this->internal; + } + + public function keyUp(): bool { + $curr = $this->getCurrentLine() - 1; + if ($curr >= 0) { + $this->setCurrentLine($curr); + + return true; + } + + return false; + } + + public function keyDown(): bool { + $curr = $this->getCurrentLine() + 1; + if ($curr < $this->getSelectableLines()) { + $this->setCurrentLine($curr); + + return true; + } + + return false; + } + + public function keyLeft(): bool { + $curr = max($this->getCurrentPage() - $this->getMaxLines(), 0); + if ($curr !== $this->getCurrentPage()) { + $this->setCurrentPage($curr); + + return true; + } + + return false; + } + + public function keyRight(): bool { +// $curr = $this->getCurrentLine() + 1; + $curr = $this->getCurrentPage() + $this->getMaxLines(); + if ($curr !== $this->getCurrentPage()) { + $this->setCurrentPage($curr); + + return true; + } + + return false; + } + + + /** + * @param bool $modified + */ + public function setModified(bool $modified): void { + $this->modified = $modified; + } + + /** + * @return bool + */ + public function isModified(): bool { + return $this->modified; + } +} + + +/** + * + */ +class TopPanel extends Panel { +} + + +/** + * + */ +class BottomLeftPanel extends Panel { + private array $items = []; + + public function onKeyItem(int $item) { + if (--$item < $this->getSelectableLines()) { + $this->setCurrentLine($item); + } + } + + /** + * @param array $items + */ + public function setItems(array $items): void { + $this->items = $items; + } + + /** + * @return array + */ + public function getItems(): array { + return $this->items; + } +} + +class BottomRightPanel extends Panel { +} + +class QuitException extends Exception { +} diff --git a/lib/Controller/DebugController.php b/lib/Controller/DebugController.php new file mode 100644 index 000000000..2c1305168 --- /dev/null +++ b/lib/Controller/DebugController.php @@ -0,0 +1,94 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Controller; + +use Exception; +use OCA\Circles\Model\Debug; +use OCA\Circles\Service\ConfigService; +use OCA\Circles\Service\DebugService; +use OCA\Circles\Service\SignedControllerService; +use OCA\Circles\Tools\Model\NCSignedRequest; +use OCA\Circles\Tools\Traits\TDeserialize; +use OCA\Circles\Tools\Traits\TNCLocalSignatory; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +class DebugController extends Controller { + use TNCLocalSignatory; + use TDeserialize; + + private SignedControllerService $signedControllerService; + private ConfigService $configService; + private DebugService $debugService; + + public function __construct( + string $appName, + IRequest $request, + SignedControllerService $signedControllerService, + ConfigService $configService, + DebugService $debugService + ) { + parent::__construct($appName, $request); + + $this->signedControllerService = $signedControllerService; + $this->configService = $configService; + $this->debugService = $debugService; + } + + + /** + * @PublicPage + * @NoCSRFRequired + * + * @return DataResponse + */ + public function debugDaemon(): DataResponse { + try { + if ($this->configService->getAppValue(ConfigService::DEBUG) !== DebugService::DEBUG_DAEMON) { + throw new Exception(); + } + + /** @var Debug $debug + * @var NCSignedRequest $signed + */ + $debug = $this->signedControllerService->extractObjectFromRequest(Debug::class, $signed); + $debug->setInstance($signed->getOrigin()); + $this->debugService->save($debug); + + return new DataResponse([]); + } catch (Exception $e) { + return $this->signedControllerService->exceptionResponse($e, Http::STATUS_UNAUTHORIZED); + } + } +} diff --git a/lib/Controller/RemoteController.php b/lib/Controller/RemoteController.php index 990bb3476..fb308d738 100644 --- a/lib/Controller/RemoteController.php +++ b/lib/Controller/RemoteController.php @@ -40,6 +40,7 @@ use OCA\Circles\Exceptions\JsonNotRequestedException; use OCA\Circles\Exceptions\UnknownInterfaceException; use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Debug; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\FederatedUser; @@ -48,6 +49,7 @@ use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; +use OCA\Circles\Service\DebugService; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\InterfaceService; use OCA\Circles\Service\MemberService; @@ -61,6 +63,7 @@ use OCA\Circles\Tools\Exceptions\SignatoryException; use OCA\Circles\Tools\Exceptions\SignatureException; use OCA\Circles\Tools\Exceptions\UnknownTypeException; +use OCA\Circles\Tools\IDeserializable; use OCA\Circles\Tools\Model\NCSignedRequest; use OCA\Circles\Tools\Model\SimpleDataStore; use OCA\Circles\Tools\Traits\TDeserialize; @@ -105,6 +108,8 @@ class RemoteController extends Controller { /** @var InterfaceService */ private $interfaceService; + private DebugService $debugService; + /** @var ConfigService */ private $configService; @@ -137,6 +142,7 @@ public function __construct( MemberService $memberService, MembershipService $membershipService, InterfaceService $interfaceService, + DebugService $debugService, ConfigService $configService, IUserSession $userSession ) { @@ -149,6 +155,7 @@ public function __construct( $this->memberService = $memberService; $this->membershipService = $membershipService; $this->interfaceService = $interfaceService; + $this->debugService = $debugService; $this->configService = $configService; $this->userSession = $userSession; @@ -195,12 +202,19 @@ public function event(): DataResponse { return $this->exceptionResponse($e, Http::STATUS_UNAUTHORIZED); } + $this->debugService->info( + 'new {`IFederatedEvent} {event.class} requested from {event.sender}', + ($event->hasCircle()) ? $event->getCircle()->getSingleId() : '', + ['event' => $event] + ); + try { $this->remoteDownstreamService->requestedEvent($event); return new DataResponse($event->getOutcome()); } catch (Exception $e) { $this->e($e, ['event' => $event]); + $this->debugService->exception($e, '', ['event' => $event]); return $this->exceptionResponse($e); } @@ -422,6 +436,43 @@ public function memberships(string $circleId): DataResponse { } + /** + * @PublicPage + * @NoCSRFRequired + * + * @return DataResponse + */ + public function debugDaemon(): DataResponse { + try { + if ($this->configService->getAppValue(ConfigService::DEBUG) !== DebugService::DEBUG_DAEMON) { + throw new Exception(); + } + + $signed = $this->remoteStreamService->incomingSignedRequest(); + $this->confirmRemoteInstance($signed); + + /** @var Debug $debug */ + $debug = $this->deserialize(json_decode($signed->getBody(), true), Debug::class); + $debug->setInstance($signed->getOrigin()); + $this->debugService->save($debug); + + return new DataResponse([]); + } catch (Exception $e) { + return $this->exceptionResponse($e, Http::STATUS_UNAUTHORIZED); + } + +// try { +// $this->remoteDownstreamService->requestedEvent($event); +// +// return new DataResponse($event->getOutcome()); +// } catch (Exception $e) { +// $this->e($e, ['event' => $event]); +// +// return $this->exceptionResponse($e); +// } + } + + /** * @return FederatedEvent * @throws InvalidItemException diff --git a/lib/Controller/SyncController.php b/lib/Controller/SyncController.php new file mode 100644 index 000000000..e2a52e043 --- /dev/null +++ b/lib/Controller/SyncController.php @@ -0,0 +1,119 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Controller; + +use Exception; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Service\DebugService; +use OCA\Circles\Service\FederatedSyncItemService; +use OCA\Circles\Service\FederatedSyncShareService; +use OCA\Circles\Service\SignedControllerService; +use OCA\Circles\Tools\Traits\TDeserialize; +use OCA\Circles\Tools\Traits\TNCLocalSignatory; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; + +class SyncController extends Controller { + use TNCLocalSignatory; + use TDeserialize; + + private SignedControllerService $signedControllerService; + private FederatedSyncItemService $federatedSyncItemService; + private FederatedSyncShareService $federatedSyncShareService; + private DebugService $debugService; + + public function __construct( + string $appName, + IRequest $request, + SignedControllerService $signedControllerService, + FederatedSyncItemService $federatedSyncItemService, + FederatedSyncShareService $federatedSyncShareService, + DebugService $debugService + ) { + parent::__construct($appName, $request); + + $this->signedControllerService = $signedControllerService; + $this->federatedSyncItemService = $federatedSyncItemService; + $this->federatedSyncShareService = $federatedSyncShareService; + $this->debugService = $debugService; + } + + + /** + * @PublicPage + * @NoCSRFRequired + * + * @return DataResponse + */ + public function getSyncedItem(): DataResponse { + try { + /** @var SyncedItem $item */ + $item = $this->signedControllerService->extractObjectFromRequest( + SyncedItem::class, + $signed + ); + + $this->debugService->info( + '{instance} is requesting details on SyncedItem {syncedItem.singleId}', '', + [ + 'instance' => $signed->getOrigin(), + 'syncedItem' => $item + ] + ); + $local = $this->federatedSyncItemService->getLocalSyncedItem($item->getSingleId(), true); + + // confirm that remote is in a circle with a share on the item + $this->federatedSyncShareService->confirmRemoteInstanceAccess( + $local->getSingleId(), + $signed->getOrigin() + ); + + $this->debugService->info( + 'SyncedItem exists, is local, and {instance} have access to the SyncedItem.', '', + [ + 'instance' => $signed->getOrigin(), + 'local' => $local, + ] + ); + +// $this->federatedSyncItemService->get + return new DataResponse($this->serialize($local)); + } catch (Exception $e) { + $this->e($e); + + return $this->signedControllerService->exceptionResponse($e, Http::STATUS_UNAUTHORIZED); + } + } + +} diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index f54e94aa3..5297f0601 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -79,6 +79,10 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { public const TOKEN = 'tk'; public const OPTIONS = 'pt'; public const HELPER = 'hp'; + public const SYNC_ITEM = 'si'; + public const SYNC_SHARE = 'ss'; + public const SYNC_LOCK = 'sl'; + public const DEBUG = 'bg'; public static $SQL_PATH = [ @@ -227,7 +231,11 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { self::BASED_ON ] ] - ] + ], + self::SYNC_ITEM => [], + self::SYNC_SHARE => [], + self::SYNC_LOCK => [], + self::DEBUG => [] ]; @@ -320,6 +328,22 @@ public function limitToSingleId(string $singleId): void { } + /** + * @param string $appId + */ + public function limitToAppId(string $appId): void { + $this->limit('app_id', $appId, '', true); + } + + + /** + * @param string $itemType + */ + public function limitToItemType(string $itemType): void { + $this->limit('item_type', $itemType, '', true); + } + + /** * @param string $itemId */ @@ -1079,7 +1103,8 @@ public function leftJoinShareToken(string $alias, string $field = ''): void { * @param string $alias * @param IFederatedUser $user * @param string $field - * @param string $helperAlias + * @param string $helperAlias - must only be filled when called from CirclesQueryHelper + * @param array $helperMoreFields - must only be filled when called from CirclesQueryHelper * * @return ICompositeExpression * @throws RequestBuilderException @@ -1088,9 +1113,10 @@ public function limitToInitiator( string $alias, IFederatedUser $user, string $field = '', - string $helperAlias = '' + string $helperAlias = '', + array $helperMoreFields = [] ): ICompositeExpression { - $this->leftJoinInitiator($alias, $user, $field, $helperAlias); + $this->leftJoinInitiator($alias, $user, $field, $helperAlias, $helperMoreFields); $where = $this->limitInitiatorVisibility($alias); $aliasInitiator = $this->generateAlias($alias, self::INITIATOR, $options); @@ -1129,8 +1155,9 @@ public function leftJoinCircleConfig(string $alias): void { * * @param string $alias * @param IFederatedUser $initiator - * @param string $field - * @param string $helperAlias + * @param string $coreField + * @param string $helperAlias - must only be filled when called from CirclesQueryHelper + * @param array $helperMoreFields - must only be filled when called from CirclesQueryHelper * * @throws RequestBuilderException */ @@ -1138,24 +1165,37 @@ public function leftJoinInitiator( string $alias, IFederatedUser $initiator, string $field = '', - string $helperAlias = '' + string $helperAlias = '', + array $helperMoreFields = [] ): void { if ($this->getType() !== QueryBuilder::SELECT) { return; } + if (!empty($helperMoreFields)) { + $helperMoreFields[] = $helperAlias . '.' . $field; + } + $expr = $this->expr(); $field = ($field === '') ? 'unique_id' : $field; $helperAlias = ($helperAlias !== '') ? $helperAlias : $alias; + $aliasMembership = $this->generateAlias($alias, self::MEMBERSHIPS, $options); + $orXMembershipFields = $expr->orX(); + foreach ($helperMoreFields as $f) { + $orXMembershipFields->add($expr->eq($aliasMembership . '.circle_id', $f)); + } + $this->leftJoin( $helperAlias, CoreRequestBuilder::TABLE_MEMBERSHIP, $aliasMembership, $expr->andX( $this->exprLimit('single_id', $initiator->getSingleId(), $aliasMembership), - $expr->eq($aliasMembership . '.circle_id', $helperAlias . '.' . $field) + (empty($helperMoreFields)) ? + $expr->eq($aliasMembership . '.circle_id', $helperAlias . '.' . $field) : + $orXMembershipFields ) ); @@ -1163,8 +1203,8 @@ public function leftJoinInitiator( $listMembershipCircleAlias = [$aliasMembership]; if ($this->getBool('initiatorDirectMember', $options, false)) { try { - $aliasDirectInitiator = $this->generateAlias($alias, self::DIRECT_INITIATOR, $options); - $listMembershipCircleAlias[] = $aliasDirectInitiator; + $aliasDirect = $this->generateAlias($alias, self::DIRECT_INITIATOR, $options); + $listMembershipCircleAlias[] = $aliasDirect; } catch (RequestBuilderException $e) { // meaning that this path does not require DIRECT_INITIATOR; can be safely ignored } @@ -1202,15 +1242,23 @@ function (string $alias) use ($orXMembershipCircle, $aliasMembershipCircle) { // bypass memberships if ($this->getBool('initiatorDirectMember', $options, false)) { try { - $aliasDirectInitiator = $this->generateAlias($alias, self::DIRECT_INITIATOR, $options); - $this->generateMemberSelectAlias($aliasDirectInitiator) + $aliasDirect = $this->generateAlias($alias, self::DIRECT_INITIATOR, $options); + + $orXDirectFields = $expr->orX(); + foreach ($helperMoreFields as $f) { + $orXDirectFields->add($expr->eq($aliasMembership . '.circle_id', $f)); + } + + $this->generateMemberSelectAlias($aliasDirect) ->leftJoin( $helperAlias, CoreRequestBuilder::TABLE_MEMBER, - $aliasDirectInitiator, + $aliasDirect, $expr->andX( - $this->exprLimit('single_id', $initiator->getSingleId(), $aliasDirectInitiator), - $expr->eq($aliasDirectInitiator . '.circle_id', $helperAlias . '.' . $field) + $this->exprLimit('single_id', $initiator->getSingleId(), $aliasDirect), + (empty($helperMoreFields)) ? + $expr->eq($aliasDirect . '.circle_id', $helperAlias . '.' . $field) : + $orXDirectFields ) ); } catch (RequestBuilderException $e) { diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index 41a5cea71..6101dbc1c 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -57,8 +57,12 @@ class CoreRequestBuilder { public const TABLE_MOUNT = 'circles_mount'; public const TABLE_MOUNTPOINT = 'circles_mountpoint'; - // wip - public const TABLE_SHARE_LOCK = 'circles_share_lock'; + public const TABLE_SYNC_ITEM = 'circles_item'; + public const TABLE_SYNC_SHARE = 'circles_share'; + public const TABLE_SYNC_LOCK = 'circles_lock'; + + public const TABLE_DEBUG = 'circles_debug'; + public const TABLE_TOKEN = 'circles_token'; public const TABLE_GSSHARES = 'circle_gsshares'; // rename ? @@ -139,7 +143,37 @@ class CoreRequestBuilder { 'mountpoint_hash' ], self::TABLE_MOUNTPOINT => [], - self::TABLE_SHARE_LOCK => [], + self::TABLE_SYNC_ITEM => [ + 'id', + 'single_id', + 'instance', + 'app_id', + 'item_type', + 'item_id', + 'checksum', + 'deleted' + ], + self::TABLE_SYNC_SHARE => [ + 'id', + 'single_id', + 'circle_id' + ], + self::TABLE_SYNC_LOCK => [ + 'id', + 'single_id', + 'update_type', + 'update_type_id', + 'time' + ], + self::TABLE_DEBUG => [ + 'id', + 'thread', + 'type', + 'circle_id', + 'instance', + 'debug', + 'time' + ], self::TABLE_TOKEN => [ 'id', 'share_id', diff --git a/lib/Db/DebugRequest.php b/lib/Db/DebugRequest.php new file mode 100644 index 000000000..0a06492b9 --- /dev/null +++ b/lib/Db/DebugRequest.php @@ -0,0 +1,100 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Db; + +use OCA\Circles\Model\Debug; + +/** + * Class ShareRequest + * + * @package OCA\Circles\Db + */ +class DebugRequest extends DebugRequestBuilder { + + + /** + * @param Debug $debug + */ + public function save(Debug $debug): void { + $qb = $this->getDebugInsertSql(); + $qb->setValue('thread', $qb->createNamedParameter($debug->getThread())) + ->setValue('type', $qb->createNamedParameter($debug->getType())) + ->setValue('circle_id', $qb->createNamedParameter($debug->getCircleId())) + ->setValue('instance', $qb->createNamedParameter($debug->getInstance())) + ->setValue('debug', $qb->createNamedParameter(json_encode($debug->getDebug()))) + ->setValue('time', $qb->createNamedParameter($debug->getTime())); + + $qb->execute(); + } + + + /** + * @param int $id + * + * @return array + */ + public function since(int $id): array { + $qb = $this->getDebugSelectSql(); + $qb->gt('id', $id); + + return $this->getItemsFromRequest($qb); + } + + + /** + * @param int $history + * + * @return Debug[] + */ + public function getHistory(int $history): array { + $qb = $this->getDebugSelectSql(); + + $qb->orderBy('id', 'desc'); + $qb->paginate($history); + + return $this->getItemsFromRequest($qb); + } + + /** + * @param int $lastId + * + * @return Debug[] + */ + public function getSince(int $lastId): array { + $qb = $this->getDebugSelectSql(); + + $qb->orderBy('id', 'desc'); + $qb->gt('id', $lastId); + + return $this->getItemsFromRequest($qb); + } +} diff --git a/lib/Db/DebugRequestBuilder.php b/lib/Db/DebugRequestBuilder.php new file mode 100644 index 000000000..d824c2d84 --- /dev/null +++ b/lib/Db/DebugRequestBuilder.php @@ -0,0 +1,116 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Db; + +use OCA\Circles\Exceptions\DebugNotFoundException; +use OCA\Circles\Model\Debug; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Exceptions\RowNotFoundException; + +class DebugRequestBuilder extends CoreRequestBuilder { + + + /** + * @return CoreQueryBuilder + */ + protected function getDebugInsertSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->insert(self::TABLE_DEBUG); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getDebugSelectSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->generateSelect( + self::TABLE_DEBUG, + self::$tables[self::TABLE_DEBUG], + CoreQueryBuilder::DEBUG + ); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getDebugUpdateSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->update(self::TABLE_DEBUG); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getDebugDeleteSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->delete(self::TABLE_DEBUG); + + return $qb; + } + + + /** + * @param CoreQueryBuilder $qb + * + * @return Debug + * @throws DebugNotFoundException + */ + public function getItemFromRequest(CoreQueryBuilder $qb): Debug { + /** @var Debug $debug */ + try { + $debug = $qb->asItem(Debug::class); + } catch (InvalidItemException | RowNotFoundException $e) { + throw new DebugNotFoundException(get_class($e)); + } + + return $debug; + } + + /** + * @param CoreQueryBuilder $qb + * + * @return Debug[] + */ + public function getItemsFromRequest(CoreQueryBuilder $qb): array { + /** @var Debug[] $result */ + return $qb->asItems(Debug::class); + } +} diff --git a/lib/Db/MemberRequest.php b/lib/Db/MemberRequest.php index 98ededbc7..bd9db7d3e 100644 --- a/lib/Db/MemberRequest.php +++ b/lib/Db/MemberRequest.php @@ -428,4 +428,25 @@ public function getAlternateSingleId(IFederatedUser $federatedUser): array { return $this->getItemsFromRequest($qb); } + + + /** + * used mainly to confirm visibility on a list of CircleIds from the point of view of a remote instance + * + * @param string $instance + * @param array $circleIds + * + * @return Member[] + * @throws RequestBuilderException + */ + public function getLinksWithInstance(string $instance, array $circleIds): array { + $qb = $this->getMemberSelectSql(); + + $qb->limitInArray('circle_id', $circleIds); + $qb->limitToInstance($instance); + $qb->gt('level', Member::LEVEL_MEMBER, true); + $qb->paginate(3); + + return $this->getItemsFromRequest($qb); + } } diff --git a/lib/Db/SyncedItemLockRequest.php b/lib/Db/SyncedItemLockRequest.php new file mode 100644 index 000000000..19a8ae595 --- /dev/null +++ b/lib/Db/SyncedItemLockRequest.php @@ -0,0 +1,61 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Db; + +use OCA\Circles\Exceptions\InvalidIdException; +use OCA\Circles\Model\SyncedItemLock; + +/** + * Class SyncedItemLockRequest + * + * @package OCA\Circles\Db + */ +class SyncedItemLockRequest extends SyncedItemLockRequestBuilder { + + + /** + * @param SyncedItemLock $lock + * + * @throws InvalidIdException + */ + public function save(SyncedItemLock $lock): void { + $this->confirmValidIds([$lock->getSingleId()]); + + $qb = $this->getSyncedItemLockInsertSql(); + $qb->setValue('single_id', $qb->createNamedParameter($lock->getSingleId())) + ->setValue('update_type', $qb->createNamedParameter($lock->getUpdateType())) + ->setValue('update_type_id', $qb->createNamedParameter($lock->getUpdateTypeId())) + ->setValue('time', $qb->createNamedParameter($lock->getTime())); + + $qb->execute(); + } +} diff --git a/lib/Db/SyncedItemLockRequestBuilder.php b/lib/Db/SyncedItemLockRequestBuilder.php new file mode 100644 index 000000000..308c7d371 --- /dev/null +++ b/lib/Db/SyncedItemLockRequestBuilder.php @@ -0,0 +1,117 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Db; + +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\Model\SyncedItemLock; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Exceptions\RowNotFoundException; + +class SyncedItemLockRequestBuilder extends CoreRequestBuilder { + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemLockInsertSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->insert(self::TABLE_SYNC_LOCK); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemLockSelectSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->generateSelect( + self::TABLE_SYNC_LOCK, + self::$tables[self::TABLE_SYNC_LOCK], + CoreQueryBuilder::SYNC_LOCK + ); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemLockUpdateSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->update(self::TABLE_SYNC_LOCK); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemLockDeleteSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->delete(self::TABLE_SYNC_LOCK); + + return $qb; + } + + + /** + * @param CoreQueryBuilder $qb + * + * @return SyncedItemLock + * @throws InvalidItemException + * @throws SyncedItemNotFoundException + */ + public function getItemFromRequest(CoreQueryBuilder $qb): SyncedItemLock { + /** @var SyncedItemLock $lock */ + try { + $lock = $qb->asItem(SyncedItemLock::class); + } catch (RowNotFoundException $e) { + throw new SyncedItemNotFoundException(); + } + + return $lock; + } + + /** + * @param CoreQueryBuilder $qb + * + * @return SyncedItemLock[] + */ + public function getItemsFromRequest(CoreQueryBuilder $qb): array { + /** @var SyncedItemLock[] $result */ + return $qb->asItems(SyncedItemLock::class); + } +} diff --git a/lib/Db/SyncedItemRequest.php b/lib/Db/SyncedItemRequest.php new file mode 100644 index 000000000..f3782e3ce --- /dev/null +++ b/lib/Db/SyncedItemRequest.php @@ -0,0 +1,100 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Db; + +use OCA\Circles\Exceptions\InvalidIdException; +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Tools\Exceptions\InvalidItemException; + +/** + * Class ShareRequest + * + * @package OCA\Circles\Db + */ +class SyncedItemRequest extends SyncedItemRequestBuilder { + + + /** + * @param SyncedItem $item + * + * @throws InvalidIdException + */ + public function save(SyncedItem $item): void { + $this->confirmValidId($item->getSingleId()); + + $qb = $this->getSyncedItemInsertSql(); + $qb->setValue('single_id', $qb->createNamedParameter($item->getSingleId())) + ->setValue('instance', $qb->createNamedParameter($qb->getInstance($item))) + ->setValue('app_id', $qb->createNamedParameter($item->getAppId())) + ->setValue('item_type', $qb->createNamedParameter($item->getItemType())) + ->setValue('item_id', $qb->createNamedParameter($item->getItemId())) + ->setValue('checksum', $qb->createNamedParameter($item->getChecksum())) + ->setValue('deleted', $qb->createNamedParameter($item->isDeleted())); + + $qb->execute(); + } + + + /** + * @param string $singleId + * + * @return SyncedItem + * @throws SyncedItemNotFoundException + */ + public function getSyncedItemFromSingleId(string $singleId): SyncedItem { + $qb = $this->getSyncedItemSelectSql(); + + $qb->limitToSingleId($singleId); + + return $this->getItemFromRequest($qb); + } + + + /** + * @param string $appId + * @param string $itemType + * @param string $itemId + * + * @return SyncedItem + * @throws SyncedItemNotFoundException + */ + public function getSyncedItem(string $appId, string $itemType, string $itemId): SyncedItem { + $qb = $this->getSyncedItemSelectSql(); + + $qb->limitToAppId($appId); + $qb->limitToItemType($itemType); + $qb->limitToItemId($itemId); + + return $this->getItemFromRequest($qb); + } +} diff --git a/lib/Db/SyncedItemRequestBuilder.php b/lib/Db/SyncedItemRequestBuilder.php new file mode 100644 index 000000000..c5e5e88c2 --- /dev/null +++ b/lib/Db/SyncedItemRequestBuilder.php @@ -0,0 +1,116 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Db; + +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Exceptions\RowNotFoundException; + +class SyncedItemRequestBuilder extends CoreRequestBuilder { + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemInsertSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->insert(self::TABLE_SYNC_ITEM); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemSelectSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->generateSelect( + self::TABLE_SYNC_ITEM, + self::$tables[self::TABLE_SYNC_ITEM], + CoreQueryBuilder::SYNC_ITEM + ); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemUpdateSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->update(self::TABLE_SYNC_ITEM); + + return $qb; + } + + + /** + * @return CoreQueryBuilder + */ + protected function getSyncedItemDeleteSql(): CoreQueryBuilder { + $qb = $this->getQueryBuilder(); + $qb->delete(self::TABLE_SYNC_ITEM); + + return $qb; + } + + + /** + * @param CoreQueryBuilder $qb + * + * @return SyncedItem + * @throws SyncedItemNotFoundException + */ + public function getItemFromRequest(CoreQueryBuilder $qb): SyncedItem { + /** @var SyncedItem $item */ + try { + $item = $qb->asItem(SyncedItem::class); + } catch (InvalidItemException | RowNotFoundException $e) { + throw new SyncedItemNotFoundException(get_class($e)); + } + + return $item; + } + + /** + * @param CoreQueryBuilder $qb + * + * @return SyncedItem[] + */ + public function getItemsFromRequest(CoreQueryBuilder $qb): array { + /** @var SyncedItem[] $result */ + return $qb->asItems(SyncedItem::class); + } +} diff --git a/lib/Db/ShareLockRequest.php b/lib/Db/SyncedShareRequest.php similarity index 56% rename from lib/Db/ShareLockRequest.php rename to lib/Db/SyncedShareRequest.php index d1301da56..5a974b581 100644 --- a/lib/Db/ShareLockRequest.php +++ b/lib/Db/SyncedShareRequest.php @@ -31,50 +31,63 @@ namespace OCA\Circles\Db; -use OCA\Circles\Exceptions\FederatedShareNotFoundException; use OCA\Circles\Exceptions\InvalidIdException; -use OCA\Circles\Model\Federated\FederatedShare; +use OCA\Circles\Exceptions\SyncedShareNotFoundException; +use OCA\Circles\Model\SyncedShare; +use OCP\DB\Exception; /** * Class ShareRequest * * @package OCA\Circles\Db */ -class ShareLockRequest extends ShareLockRequestBuilder { +class SyncedShareRequest extends SyncedShareRequestBuilder { /** - * @param FederatedShare $share + * @param SyncedShare $share * * @throws InvalidIdException + * @throws Exception */ - public function save(FederatedShare $share): void { - $this->confirmValidIds([$share->getItemId()]); + public function save(SyncedShare $share): void { + $this->confirmValidIds([$share->getSingleId(), $share->getCircleId()]); - $qb = $this->getShareLockInsertSql(); - $qb->setValue('item_id', $qb->createNamedParameter($share->getItemId())) - ->setValue('circle_id', $qb->createNamedParameter($share->getCircleId())) - ->setValue('instance', $qb->createNamedParameter($qb->getInstance($share))); + $qb = $this->getSyncedShareInsertSql(); + $qb->setValue('single_id', $qb->createNamedParameter($share->getSingleId())) + ->setValue('circle_id', $qb->createNamedParameter($share->getCircleId())); - $qb->execute(); + $qb->executeStatement(); } /** - * @param string $itemId + * @param string $singleId + * + * @return SyncedShare[] + */ + public function getShares(string $singleId): array { + $qb = $this->getSyncedShareSelectSql(); + + $qb->limitToSingleId($singleId); + + return $this->getItemsFromRequest($qb); + } + + /** + * @param string $itemSingleId * @param string $circleId * - * @return FederatedShare - * @throws FederatedShareNotFoundException + * @return SyncedShare + * @throws SyncedShareNotFoundException */ - public function getShare(string $itemId, string $circleId = ''): FederatedShare { - $qb = $this->getShareLockSelectSql(); + public function getShare(string $itemSingleId, string $circleId): SyncedShare { + $qb = $this->getSyncedShareSelectSql(); - $qb->limitToItemId($itemId); - if ($circleId !== '') { - $qb->limitToCircleId($circleId); - } + $qb->limitToSingleId($itemSingleId); + $qb->limitToCircleId($circleId); return $this->getItemFromRequest($qb); } + } diff --git a/lib/Db/ShareLockRequestBuilder.php b/lib/Db/SyncedShareRequestBuilder.php similarity index 58% rename from lib/Db/ShareLockRequestBuilder.php rename to lib/Db/SyncedShareRequestBuilder.php index ae9a90c75..d11a7d108 100644 --- a/lib/Db/ShareLockRequestBuilder.php +++ b/lib/Db/SyncedShareRequestBuilder.php @@ -10,7 +10,7 @@ * later. See the COPYING file. * * @author Maxence Lange - * @copyright 2021 + * @copyright 2022 * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify @@ -31,24 +31,25 @@ namespace OCA\Circles\Db; +use OCA\Circles\Exceptions\SyncedShareNotFoundException; +use OCA\Circles\Model\SyncedShare; +use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\Exceptions\RowNotFoundException; -use OCA\Circles\Exceptions\FederatedShareNotFoundException; -use OCA\Circles\Model\Federated\FederatedShare; /** * Class ShareRequestBuilder * * @package OCA\Circles\Db */ -class ShareLockRequestBuilder extends CoreRequestBuilder { +class SyncedShareRequestBuilder extends CoreRequestBuilder { /** * @return CoreQueryBuilder */ - protected function getShareLockInsertSql(): CoreQueryBuilder { + protected function getSyncedShareInsertSql(): CoreQueryBuilder { $qb = $this->getQueryBuilder(); - $qb->insert(self::TABLE_SHARE_LOCK); + $qb->insert(self::TABLE_SYNC_SHARE); return $qb; } @@ -57,12 +58,13 @@ protected function getShareLockInsertSql(): CoreQueryBuilder { /** * @return CoreQueryBuilder */ - protected function getShareLockSelectSql(): CoreQueryBuilder { + protected function getSyncedShareSelectSql(): CoreQueryBuilder { $qb = $this->getQueryBuilder(); - - $qb->select('s.id', 's.item_id', 's.circle_id', 's.instance') - ->from(self::TABLE_SHARE_LOCK, 's') - ->setDefaultSelectAlias('s'); + $qb->generateSelect( + self::TABLE_SYNC_SHARE, + self::$tables[self::TABLE_SYNC_SHARE], + CoreQueryBuilder::SYNC_SHARE + ); return $qb; } @@ -71,9 +73,9 @@ protected function getShareLockSelectSql(): CoreQueryBuilder { /** * @return CoreQueryBuilder */ - protected function getShareLockUpdateSql(): CoreQueryBuilder { + protected function getSyncedShareUpdateSql(): CoreQueryBuilder { $qb = $this->getQueryBuilder(); - $qb->update(self::TABLE_SHARE_LOCK); + $qb->update(self::TABLE_SYNC_SHARE); return $qb; } @@ -82,9 +84,9 @@ protected function getShareLockUpdateSql(): CoreQueryBuilder { /** * @return CoreQueryBuilder */ - protected function getShareDeleteSql(): CoreQueryBuilder { + protected function getSyncedShareDeleteSql(): CoreQueryBuilder { $qb = $this->getQueryBuilder(); - $qb->delete(self::TABLE_SHARE_LOCK); + $qb->delete(self::TABLE_SYNC_SHARE); return $qb; } @@ -93,27 +95,27 @@ protected function getShareDeleteSql(): CoreQueryBuilder { /** * @param CoreQueryBuilder $qb * - * @return FederatedShare - * @throws FederatedShareNotFoundException + * @return SyncedShare + * @throws SyncedShareNotFoundException */ - public function getItemFromRequest(CoreQueryBuilder $qb): FederatedShare { - /** @var FederatedShare $circle */ + public function getItemFromRequest(CoreQueryBuilder $qb): SyncedShare { + /** @var SyncedShare $lock */ try { - $circle = $qb->asItem(FederatedShare::class); - } catch (RowNotFoundException $e) { - throw new FederatedShareNotFoundException(); + $lock = $qb->asItem(SyncedShare::class); + } catch (RowNotFoundException | InvalidItemException $e) { + throw new SyncedShareNotFoundException(); } - return $circle; + return $lock; } /** * @param CoreQueryBuilder $qb * - * @return FederatedShare[] + * @return SyncedShare[] */ public function getItemsFromRequest(CoreQueryBuilder $qb): array { - /** @var FederatedShare[] $result */ - return $qb->asItems(FederatedShare::class); + /** @var SyncedShare[] $result */ + return $qb->asItems(SyncedShare::class); } } diff --git a/lib/Exceptions/CircleSharesManagerException.php b/lib/Exceptions/CircleSharesManagerException.php new file mode 100644 index 000000000..1595df54c --- /dev/null +++ b/lib/Exceptions/CircleSharesManagerException.php @@ -0,0 +1,36 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Exceptions; + +use Exception; + +class CircleSharesManagerException extends Exception { +} diff --git a/lib/Exceptions/FederatedShareBelongingException.php b/lib/Exceptions/DebugNotFoundException.php similarity index 94% rename from lib/Exceptions/FederatedShareBelongingException.php rename to lib/Exceptions/DebugNotFoundException.php index 42f7e0b1d..80b3dd3bc 100644 --- a/lib/Exceptions/FederatedShareBelongingException.php +++ b/lib/Exceptions/DebugNotFoundException.php @@ -30,5 +30,5 @@ namespace OCA\Circles\Exceptions; -class FederatedShareBelongingException extends FederatedItemException { +class DebugNotFoundException extends FederatedItemBadRequestException { } diff --git a/lib/Exceptions/FederatedSyncConflictException.php b/lib/Exceptions/FederatedSyncConflictException.php new file mode 100644 index 000000000..cfac9e77a --- /dev/null +++ b/lib/Exceptions/FederatedSyncConflictException.php @@ -0,0 +1,36 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Exceptions; + +use Exception; + +class FederatedSyncConflictException extends FederatedItemConflictException { +} diff --git a/lib/Exceptions/FederatedSyncManagerNotFoundException.php b/lib/Exceptions/FederatedSyncManagerNotFoundException.php new file mode 100644 index 000000000..5e0714481 --- /dev/null +++ b/lib/Exceptions/FederatedSyncManagerNotFoundException.php @@ -0,0 +1,36 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Exceptions; + +use Exception; + +class FederatedSyncManagerNotFoundException extends Exception { +} diff --git a/lib/Exceptions/FederatedShareAlreadyLockedException.php b/lib/Exceptions/SyncedItemNotFoundException.php similarity index 92% rename from lib/Exceptions/FederatedShareAlreadyLockedException.php rename to lib/Exceptions/SyncedItemNotFoundException.php index 993339c88..537fd309b 100644 --- a/lib/Exceptions/FederatedShareAlreadyLockedException.php +++ b/lib/Exceptions/SyncedItemNotFoundException.php @@ -30,7 +30,5 @@ namespace OCA\Circles\Exceptions; -use Exception; - -class FederatedShareAlreadyLockedException extends Exception { +class SyncedItemNotFoundException extends FederatedItemNotFoundException { } diff --git a/lib/Exceptions/SyncedShareNotFoundException.php b/lib/Exceptions/SyncedShareNotFoundException.php new file mode 100644 index 000000000..10f27377d --- /dev/null +++ b/lib/Exceptions/SyncedShareNotFoundException.php @@ -0,0 +1,34 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Exceptions; + +class SyncedShareNotFoundException extends FederatedItemNotFoundException { +} diff --git a/lib/Exceptions/FederatedShareNotFoundException.php b/lib/Exceptions/SyncedSharedAlreadyExistException.php similarity index 94% rename from lib/Exceptions/FederatedShareNotFoundException.php rename to lib/Exceptions/SyncedSharedAlreadyExistException.php index 9113fdfab..747f8c58f 100644 --- a/lib/Exceptions/FederatedShareNotFoundException.php +++ b/lib/Exceptions/SyncedSharedAlreadyExistException.php @@ -32,5 +32,5 @@ use Exception; -class FederatedShareNotFoundException extends Exception { +class SyncedSharedAlreadyExistException extends Exception { } diff --git a/lib/FederatedItems/CircleSettings.php b/lib/FederatedItems/CircleSettings.php deleted file mode 100644 index 0521c23f5..000000000 --- a/lib/FederatedItems/CircleSettings.php +++ /dev/null @@ -1,85 +0,0 @@ - - * @copyright 2021 - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - - -namespace OCA\Circles\FederatedItems; - -use OCA\Circles\Tools\Traits\TDeserialize; -use OCA\Circles\Db\CircleRequest; -use OCA\Circles\IFederatedItem; -use OCA\Circles\Model\Federated\FederatedEvent; - -/** - * Class CircleSettings - * - * @package OCA\Circles\FederatedItems - */ -class CircleSettings implements IFederatedItem { - use TDeserialize; - - - /** @var CircleRequest */ - private $circleRequest; - - - /** - * CircleSettings constructor. - * - * @param CircleRequest $circleRequest - */ - public function __construct(CircleRequest $circleRequest) { - $this->circleRequest = $circleRequest; - } - - - /** - * @param FederatedEvent $event - */ - public function verify(FederatedEvent $event): void { - $circle = $event->getCircle(); - $new = clone $circle; - $event->setOutcome($this->serialize($new)); - } - - - /** - * @param FederatedEvent $event - */ - public function manage(FederatedEvent $event): void { - } - - - /** - * @param FederatedEvent $event - * @param array $results - */ - public function result(FederatedEvent $event, array $results): void { - } -} diff --git a/lib/FederatedItems/FederatedSync/ShareCreation.php b/lib/FederatedItems/FederatedSync/ShareCreation.php new file mode 100644 index 000000000..2b7adead7 --- /dev/null +++ b/lib/FederatedItems/FederatedSync/ShareCreation.php @@ -0,0 +1,228 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\FederatedItems\FederatedSync; + +use OCA\Circles\Db\SyncedItemRequest; +use OCA\Circles\Exceptions\FederatedSyncConflictException; +use OCA\Circles\Exceptions\RequestBuilderException; +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\IFederatedItem; +use OCA\Circles\IFederatedItemAsyncProcess; +use OCA\Circles\IFederatedItemHighSeverity; +use OCA\Circles\IFederatedItemLimitedToInstanceWithMember; +use OCA\Circles\IFederatedItemSyncedItem; +use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Service\ConfigService; +use OCA\Circles\Service\DebugService; +use OCA\Circles\Service\FederatedSyncItemService; +use OCA\Circles\Service\FederatedSyncShareService; +use OCA\Circles\Tools\Traits\TDeserialize; + + +class ShareCreation implements + IFederatedItem, + IFederatedItemLimitedToInstanceWithMember, + IFederatedItemHighSeverity, + IFederatedItemAsyncProcess, + IFederatedItemSyncedItem { + use TDeserialize; + + private SyncedItemRequest $syncedItemRequest; + private FederatedSyncItemService $federatedSyncItemService; + private FederatedSyncShareService $federatedSyncShareService; + private ConfigService $configService; + private DebugService $debugService; + + + /** + * @param SyncedItemRequest $syncedItemRequest + * @param FederatedSyncItemService $federatedSyncItemService + * @param FederatedSyncShareService $federatedSyncShareService + * @param ConfigService $configService + * @param DebugService $debugService + */ + public function __construct( + SyncedItemRequest $syncedItemRequest, + FederatedSyncItemService $federatedSyncItemService, + FederatedSyncShareService $federatedSyncShareService, + ConfigService $configService, + DebugService $debugService + ) { + $this->syncedItemRequest = $syncedItemRequest; + $this->federatedSyncItemService = $federatedSyncItemService; + $this->federatedSyncShareService = $federatedSyncShareService; + $this->configService = $configService; + $this->debugService = $debugService; + } + + + /** + * @param FederatedEvent $event + * + * @throws FederatedSyncConflictException + */ + public function verify(FederatedEvent $event): void { + $circle = $event->getCircle(); + $syncedItem = $event->getSyncedItem(); +// $initiator = $circle->getInitiator(); + + $syncedItem->setInstance($event->getOrigin()); + + try { + $this->compareWithKnownItemId($syncedItem); + $this->compareWithKnownSingleId($syncedItem); + } catch (FederatedSyncConflictException $e) { + $this->debugService->exception( + $e, '', + [ + 'note' => 'WIP: exception is thrown and catch to async process; while returning error', + 'note2' => 'async process will try to fix the conflict' + ] + ); + // TODO: manage FederatedSyncConflictException - should not be run 'live' at this point + // The solution might be to Async the current process with an error while fixing the issue + // on the child process. remote instance will tell the initiator that there is an issue and + // he should try again (estimating the process to fix conflict might takes few seconds. + // To do so, catching the exception earlier instead of here. + throw $e; + } catch (SyncedItemNotFoundException $e) { + $this->debugService->info( + 'no known syncedItem {syncedItem.singleId} were found in database, assuming this is good', + '', + ['syncedItem' => $syncedItem] + ); + } + } + + + /** + * @param FederatedEvent $event + * + * @throws RequestBuilderException + */ + public function manage(FederatedEvent $event): void { + if ($this->configService->isLocalInstance($event->getOrigin())) { + $this->debugService->info( + '{`FederatedEvent} has its origin set as current instance. leaving.', '', + ['event' => $event] + ); + + return; + } + + $circle = $event->getCircle(); + $syncedItem = $event->getSyncedItem(); + + try { + $this->compareWithKnownItemId($syncedItem); + $this->compareWithKnownSingleId($syncedItem); + } catch (FederatedSyncConflictException $e) { + $this->debugService->exception( + $e, '', + ['note' => 'WIP: this exception should start the process of fixing conflict'] + ); + + return; // TODO: manage FederatedSyncConflictException - can be done 'live' at this point + } catch (SyncedItemNotFoundException $e) { + } + + $extraData = $event->getParams()->gArray('extraData'); + + $this->federatedSyncItemService->updateSyncedItem($syncedItem); + $this->federatedSyncShareService->syncShareCreation($syncedItem, $circle, $extraData); + } + + + /** + * @param FederatedEvent $event + * @param array $results + */ + public function result(FederatedEvent $event, array $results): void { + } + + + /** + * @throws FederatedSyncConflictException + * @throws SyncedItemNotFoundException + */ + private function compareWithKnownSingleId(SyncedItem $syncedItem): void { + $knownItem = $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); + $this->debugService->info( + 'Comparing with the SyncedItem {syncedItem.singleId} from database: {knownItem.appId}.{knownItem.itemType}.{knownItem.itemId}', + '', + [ + 'syncedItem' => $syncedItem, + 'knownItem' => $knownItem + ] + ); + + if ($knownItem->getAppId() !== $syncedItem->getAppId() + || $knownItem->getItemType() !== $syncedItem->getItemType() + || $knownItem->getInstance() !== $syncedItem->getInstance() + || $knownItem->isDeleted()) { + throw new FederatedSyncConflictException('conflict/dsync on SyncedItem'); + } + } + + + /** + * @param SyncedItem $syncedItem + * + * @throws FederatedSyncConflictException + */ + private function compareWithKnownItemId(SyncedItem $syncedItem): void { + try { + $knownItem = $this->syncedItemRequest->getSyncedItem( + $syncedItem->getAppId(), + $syncedItem->getItemType(), + $syncedItem->getItemId() + ); + } catch (SyncedItemNotFoundException $e) { + return; + } + + $this->debugService->info( + 'Comparing with the SyncedItem {syncedItem.appId}.{syncedItem.itemType}.{syncedItem.itemId} from database: {knownItem.singleId}', + '', + [ + 'syncedItem' => $syncedItem, + 'knownItem' => $knownItem + ] + ); + + if ($knownItem->getSingleId() !== $syncedItem->getSingleId()) { + throw new FederatedSyncConflictException('conflict/dsync on SyncedItem'); + } + } + +} diff --git a/lib/FederatedItems/ItemLock.php b/lib/FederatedItems/ItemLock.php deleted file mode 100644 index f3254a66d..000000000 --- a/lib/FederatedItems/ItemLock.php +++ /dev/null @@ -1,130 +0,0 @@ - - * @copyright 2017 - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - - -namespace OCA\Circles\FederatedItems; - -use OCA\Circles\Tools\Traits\TStringTools; -use OCA\Circles\Db\ShareLockRequest; -use OCA\Circles\Exceptions\FederatedShareNotFoundException; -use OCA\Circles\Exceptions\InvalidIdException; -use OCA\Circles\IFederatedItem; -use OCA\Circles\IFederatedItemDataRequestOnly; -use OCA\Circles\Model\Federated\FederatedEvent; -use OCA\Circles\Model\Federated\FederatedShare; - -/** - * Class ItemLock - * - * @package OCA\Circles\FederatedItems - */ -class ItemLock implements - IFederatedItem, - IFederatedItemDataRequestOnly { - use TStringTools; - - - public const STATUS_LOCKED = 'locked'; - public const STATUS_ALREADY_LOCKED = 'already_locked'; - public const STATUS_INSTANCE_LOCKED = 'instance_locked'; - - - /** @var ShareLockRequest */ - private $shareLockRequest; - - - /** - * ItemLock constructor. - * - * @param ShareLockRequest $shareLockRequest - */ - public function __construct(ShareLockRequest $shareLockRequest) { - $this->shareLockRequest = $shareLockRequest; - } - - - /** - * create lock in db if the lock does not exist for this circle. - * will fail if the lock already exist for anothr instance, even for another circle - * - * @param FederatedEvent $event - * - * @throws InvalidIdException - * @throws FederatedShareNotFoundException - */ - public function verify(FederatedEvent $event): void { - $itemId = $event->getParams()->g('itemId'); - $this->shareLockRequest->confirmValidId($itemId); - - $status = ''; - try { - $known = $this->shareLockRequest->getShare($itemId); - - if ($known->getInstance() === $event->getSender()) { - $status = self::STATUS_ALREADY_LOCKED; - $known = $this->shareLockRequest->getShare($itemId, $event->getCircle()->getSingleId()); - } else { - $status = self::STATUS_INSTANCE_LOCKED; - } - } catch (FederatedShareNotFoundException $e) { - $share = new FederatedShare(); - $share->setItemId($itemId); - $share->setCircleId($event->getCircle()->getSingleId()); - $share->setInstance($event->getSender()); - - $this->shareLockRequest->save($share); - $known = $this->shareLockRequest->getShare($itemId); - if ($status === '') { - $status = self::STATUS_LOCKED; - } - } - - $known->setLockStatus($status); - $event->setOutcome(['federatedShare' => $known]); - } - - - /** - * @param FederatedEvent $event - */ - public function manage(FederatedEvent $event): void { -// $this->circleEventService->onSharedItemsSyncRequested($event); -// -// $event->setResult(new SimpleDataStore(['shares' => 'ok'])); - } - - - /** - * @param FederatedEvent $event - * @param array $results - */ - public function result(FederatedEvent $event, array $results): void { - } -} diff --git a/lib/FederatedItems/SharedItemsSync.php b/lib/FederatedItems/SharedItemsSync.php index ff7edcc58..8af158f1d 100644 --- a/lib/FederatedItems/SharedItemsSync.php +++ b/lib/FederatedItems/SharedItemsSync.php @@ -33,7 +33,7 @@ use OCA\Circles\Tools\Model\SimpleDataStore; use OCA\Circles\IFederatedItem; -use OCA\Circles\IFederatedItemLimitedToInstanceWithMembership; +use OCA\Circles\IFederatedItemLimitedToInstanceWithMember; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Service\CircleEventService; @@ -44,7 +44,7 @@ */ class SharedItemsSync implements IFederatedItem, - IFederatedItemLimitedToInstanceWithMembership { + IFederatedItemLimitedToInstanceWithMember { // TODO: testing that IFederatedItemLimitedToInstanceWithMembership is working (since multi-instance) diff --git a/lib/ICircleSharesManager.php b/lib/ICircleSharesManager.php new file mode 100644 index 000000000..2785343a9 --- /dev/null +++ b/lib/ICircleSharesManager.php @@ -0,0 +1,101 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles; + +/** + * Interface IShareManager + * + * @package OCA\Circles + */ +interface ICircleSharesManager { + + /** + * Register a IFederatedSyncManager + * + * This is the first step to set up in `Application.php` of any app willing to use the + * FederatedItem feature: + * + * public function boot(IBootContext $context): void { + * $circleManager = $context->getAppContainer()->get(CirclesManager::class); + * $circleManager->getShareManager() + * ->registerFederatedSyncManager(TestFederatedSync::class); + * } + * + * @param string $syncManager the class that implemented IFederatedSyncManager + */ + public function registerFederatedSyncManager(string $syncManager): void; + + /** + * Initiate a share of an item to a circle. + * Your app can add some extraData about the share that can be needed during the process + * + * @param string $itemId + * @param string $circleId + * @param array $extraData + */ + public function createShare(string $itemId, string $circleId, array $extraData = []): void; + + /** + * Initiate an update on a share. (ie. permissions) + * Your app can add some extraData about the share that can be needed during the process + * + * @param string $itemId + * @param string $circleId + * @param array $extraData + */ + public function updateShare(string $itemId, string $circleId, array $extraData = []): void; + + /** + * Initiate the deletion of a share + * + * @param string $itemId + * @param string $circleId + */ + public function deleteShare(string $itemId, string $circleId): void; + + /** + * Initiate the update of a share + * $serializedData contains the serialized data of the item that will be used during the process by your + * app to update that content in its table + * + * @param string $itemId + * @param array $extraData + */ + public function updateItem(string $itemId, array $extraData): void; + + /** + * Initiate the deletion of an Item + * + * @param string $itemId + */ + public function deleteItem(string $itemId): void; +} diff --git a/lib/IFederatedItemLimitedToInstanceWithMembership.php b/lib/IFederatedItemLimitedToInstanceWithMember.php similarity index 95% rename from lib/IFederatedItemLimitedToInstanceWithMembership.php rename to lib/IFederatedItemLimitedToInstanceWithMember.php index 00333aa57..afe456b43 100644 --- a/lib/IFederatedItemLimitedToInstanceWithMembership.php +++ b/lib/IFederatedItemLimitedToInstanceWithMember.php @@ -36,5 +36,5 @@ * * @package OCA\Circles */ -interface IFederatedItemLimitedToInstanceWithMembership { +interface IFederatedItemLimitedToInstanceWithMember { } diff --git a/lib/IFederatedItemSyncedItem.php b/lib/IFederatedItemSyncedItem.php new file mode 100644 index 000000000..4ae1cdb2f --- /dev/null +++ b/lib/IFederatedItemSyncedItem.php @@ -0,0 +1,42 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles; + +/** + * SyncedItem from IFederatedItem will be check: + * + * - SyncedItem needs to be present + * - SyncedItem needs to come from the same instance that the request + */ +interface IFederatedItemSyncedItem { + +} diff --git a/lib/IFederatedSyncManager.php b/lib/IFederatedSyncManager.php new file mode 100644 index 000000000..c10ec0998 --- /dev/null +++ b/lib/IFederatedSyncManager.php @@ -0,0 +1,293 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles; + +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\Model\FederatedUser; +use OCA\Circles\Model\Membership; + +/** + * Interface IFederatedSyncManager + * + * @package OCA\Circles + */ +interface IFederatedSyncManager { + + + /** + * The string that id the app, must be unique. + * + * @return string + */ + public function getAppId(): string; + + /** + * The same app can manage FederatedItem on multiple types of items. + * If this is the case, your app will need to register as many IFederatedSyncManager than types + * of items to be managed. + * + * Each IFederatedSyncManager will use a different string to identify each type of items. + * + * @return string + */ + public function getItemType(): string; + + /** + * because there can be exchange between different version of your app you can keep trace of + * used version + * + * @return int + */ + public function getApiVersion(): int; + + /** + * limit to exchange only with Api that are equal or above this value + * + * @return int + */ + public function getApiLowerBackCompatibility(): int; + + /** + * return true if FullSupport + * + * @return bool + */ + public function isFullSupport(): bool; + + + /** + * The method is called during data synchronisation, to serialize an item. + * Your app need to return the item as an array based on itemId + * + * @param string $itemId + * + * @return array + * @throws SyncedItemNotFoundException + */ + public function serializeItem(string $itemId): array; + + + /** + * This method is called when data with different checksum is received from the instance that created the + * shared item. + * $serializedData is the array returned by serializeItem(itemId). + * + * Your app needs to update the information related to the item identified by itemId in its own + * table. + * + * IMPORTANT: If itemId is contained within the serialized data of an item, your app needs to + * compare $itemId with the itemId stored within the $serializedData + * + * @param string $itemId + * @param array $serializedData + */ + public function syncItem(string $itemId, array $serializedData): void; + + + /** + * Your app returns details about a share. + * Method will be called to re-sync a share on a remote instance + * + * @param string $itemId + * @param string $circleId + * + * @return array + */ + public function getShareDetails(string $itemId, string $circleId): array; + + /** + * Force an update of the share, based on the $extraData returned by getShareDetails() + * + * @param string $itemId + * @param string $circleId + * @param array $extraData + */ + public function syncShare(string $itemId, string $circleId, array $extraData): void; + + + /** + * Your app returns if the share is creatable at that point. + * Method is only called on the instance that owns the shared item + * + * @param string $itemId + * @param string $circleId + * @param array $extraData + * @param FederatedUser $federatedUser + * + * @return bool + */ + public function isShareCreatable( + string $itemId, + string $circleId, + array $extraData, + FederatedUser $federatedUser + ): bool; + + + /** + * Is called when the share looks valid. + * Method is called on every instance. + * + * In this method, your app needs to create its own entries in its table regarding the new share + * + * $extraData is the array sent when your app initiated the process with + * ICircleSharesManager::createShare(itemId, circleId, extraData); + * + * Note: In case of isFullSupport() returns false, it will not be executed on the instance that owns the + * item. + * + * $membership contains enough data about the author of the share for your app to generate its + * own event (activity, mail, ...) + * + * @param string $itemId + * @param string $circleId + * @param array $extraData + * @param FederatedUser $federatedUser + */ + public function onShareCreation( + string $itemId, + string $circleId, + array $extraData, + FederatedUser $federatedUser + ): void; + + + /** + * Your app returns if the share is modifiable at that point. + * Method is only called on the instance that owns the shared item + * + * @param string $itemId + * @param string $circleId + * @param array $extraData + * @param Membership $membership + * + * @return bool + */ + public function isShareModifiable( + string $itemId, + string $circleId, + array $extraData, + Membership $membership + ): bool; + + + /** + * Is called when the share looks valid. + * Method is called on every instance. + * + * In this method, your app needs to update its own entries in its table the modified share + * + * $extraData is the array sent when your app initiated the process with + * ICircleSharesManager::updateShare(itemId, circleId, extraData); + * + * Note: In case of $fullSupport===false when registering the IFederateShareManager, it will not be + * executed on the instance that owns the item. + * + * $membership contains enough data about the author of the share for your app to generate its + * own event (activity, mail, ...) + * + * @param string $itemId + * @param string $circleId + * @param array $extraData + * @param Membership $membership + */ + public function onShareModification( + string $itemId, + string $circleId, + array $extraData, + Membership $membership + ): void; + + + /** + * Your app returns if the share is deletable at that point. + * Method is only called on the instance that owns the shared item + * + * @param string $itemId + * @param string $circleId + * @param Membership $membership + * + * @return bool + */ + public function isShareDeletable( + string $itemId, + string $circleId, + Membership $membership + ): bool; + + + /** + * Is called when the share is supposed to be deleted. + * Method is called on every instance. + * + * In this method, your app needs to delete its own entries in its table about the deleted share + * + * Note: In case of $fullSupport===false when registering the IFederateShareManager, it will not be + * executed on the instance that owns the item. + * + * $membership contains enough data about the author of the share for your app to generate its + * own event (activity, mail, ...) + * + * @param string $itemId + * @param string $circleId + * @param Membership $membership + */ + public function onShareDeletion( + string $itemId, + string $circleId, + Membership $membership + ): void; + + + /** + * Your app returns if the item can be updated by $federatedUser. + * + * Membership of $federatedUser can go through multiple paths as the same item can be shared to different + * circles $federatedUser is a member. Meaning multiple permissions needs to be checked. + * + * $serializedData can be modified/fixed within the method before being stored. Maybe some data cannot be + * edited based on permissions + * + * Method is only called on the instance that owns the shared item + * + * @param string $itemId + * @param array $extraData + * @param FederatedUser $federatedUser + * + * @return bool + */ + public function isItemUpdatable( + string $itemId, + array $extraData, + FederatedUser $federatedUser + ): bool; +} diff --git a/lib/IReferencedObject.php b/lib/IReferencedObject.php new file mode 100644 index 000000000..985c2b5d7 --- /dev/null +++ b/lib/IReferencedObject.php @@ -0,0 +1,34 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Tools; + +interface IReferencedObject extends IDeserializable { +} diff --git a/lib/Migration/Version0025Date20220510104622.php b/lib/Migration/Version0025Date20220510104622.php new file mode 100644 index 000000000..f68192939 --- /dev/null +++ b/lib/Migration/Version0025Date20220510104622.php @@ -0,0 +1,243 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Migration; + +use Closure; +use Doctrine\DBAL\Schema\SchemaException; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version0025Date20220510104622 extends SimpleMigrationStep { + + + /** + * @param IDBConnection $connection + */ + public function __construct(IDBConnection $connection) { + } + + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * + * @return null|ISchemaWrapper + * @throws SchemaException + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('circles_item')) { + $table = $schema->createTable('circles_item'); + $table->addColumn( + 'id', Types::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ] + ); + $table->addColumn( + 'single_id', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'instance', Types::STRING, [ + 'notnull' => false, + 'length' => 255, + ] + ); + $table->addColumn( + 'app_id', Types::STRING, [ + 'length' => 255, + 'notnull' => false + ] + ); + $table->addColumn( + 'item_type', Types::STRING, [ + 'length' => 127, + 'notnull' => false + ] + ); + $table->addColumn( + 'item_id', Types::STRING, [ + 'length' => 63, + 'notnull' => false + ] + ); + $table->addColumn( + 'checksum', Types::STRING, [ + 'length' => 127, + 'notnull' => false + ] + ); + $table->addColumn( + 'deleted', Types::BOOLEAN, [ + 'notnull' => false, + 'default' => false + ] + ); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['single_id']); + $table->addIndex(['app_id', 'item_type', 'item_id'], 'c_aiitii'); + } + + if (!$schema->hasTable('circles_share')) { + $table = $schema->createTable('circles_share'); + $table->addColumn( + 'id', Types::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ] + ); + $table->addColumn( + 'single_id', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'circle_id', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['single_id', 'circle_id'], 'c_sici'); + } + + if (!$schema->hasTable('circles_lock')) { + $table = $schema->createTable('circles_lock'); + $table->addColumn( + 'id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + ] + ); + $table->addColumn( + 'single_id', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'update_type', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'update_type_id', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'time', Types::INTEGER, [ + 'notnull' => false, + 'length' => 7, + 'unsigned' => true + ] + ); + + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['single_id', 'update_type', 'update_type_id'], 'c_siututi'); + } + + if (!$schema->hasTable('circles_debug')) { + $table = $schema->createTable('circles_debug'); + $table->addColumn( + 'id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + 'length' => 14, + 'unsigned' => true, + ] + ); + $table->addColumn( + 'thread', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'type', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'circle_id', Types::STRING, [ + 'notnull' => false, + 'length' => 31, + ] + ); + $table->addColumn( + 'instance', Types::STRING, [ + 'notnull' => false, + 'length' => 127, + ] + ); + $table->addColumn( + 'debug', Types::TEXT, [ + 'notnull' => false + ] + ); + $table->addColumn( + 'time', Types::INTEGER, [ + 'notnull' => false, + 'length' => 7, + 'unsigned' => true + ] + ); + + $table->setPrimaryKey(['id']); + $table->addIndex(['circle_id', 'instance'], 'circles_debug_cii'); + $table->addIndex(['time']); + } + + return $schema; + } +} diff --git a/lib/Model/Circle.php b/lib/Model/Circle.php index 03c54e394..e2c22ce48 100644 --- a/lib/Model/Circle.php +++ b/lib/Model/Circle.php @@ -50,6 +50,7 @@ use OCA\Circles\Tools\Db\IQueryRow; use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; use OCA\Circles\Tools\Traits\TArrayTools; use OCA\Circles\Tools\Traits\TDeserialize; use OCP\Security\IHasher; @@ -82,7 +83,11 @@ * * @package OCA\Circles\Model */ -class Circle extends ManagedModel implements IEntity, IDeserializable, IQueryRow, JsonSerializable { +class Circle extends ManagedModel implements IEntity, + IReferencedObject, + IQueryRow, + JsonSerializable { + use TArrayTools; use TDeserialize; diff --git a/lib/Model/Debug.php b/lib/Model/Debug.php new file mode 100644 index 000000000..a98cad2b7 --- /dev/null +++ b/lib/Model/Debug.php @@ -0,0 +1,277 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Model; + +use JetBrains\PhpStorm\ArrayShape; +use JetBrains\PhpStorm\Pure; +use JsonSerializable; +use OCA\Circles\Tools\Db\IQueryRow; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; +use OCA\Circles\Tools\Model\ReferencedDataStore; +use OCA\Circles\Tools\Traits\TArrayTools; +use OCA\Circles\Tools\Traits\TDeserialize; + +class Debug implements + IReferencedObject, + IQueryRow, + JsonSerializable { + + use TArrayTools; + use TDeserialize; + + private int $id; + private string $thread; + private string $type; + private string $circleId; + private string $instance = ''; + private ReferencedDataStore $debug; + private int $time = 0; + + + /** + * @param ReferencedDataStore|null $data + * @param string $circleId + */ + public function __construct( + ?ReferencedDataStore $data = null, + string $circleId = '', + string $thread = '', + string $type = '' + ) { + if (!is_null($data)) { + $this->setDebug($data); + } + + $this->setThread($thread); + $this->setCircleId($circleId); + $this->setType($type); + } + + + /** + * @param int $id + * + * @return Debug + */ + public function setId(int $id): self { + $this->id = $id; + + return $this; + } + + /** + * @return int + */ + public function getId(): int { + return $this->id; + } + + + /** + * @param string $thread + * + * @return Debug + */ + public function setThread(string $thread): self { + $this->thread = $thread; + + return $this; + } + + /** + * @return string + */ + public function getThread(): string { + return $this->thread; + } + + + /** + * @param string $type + * + * @return Debug + */ + public function setType(string $type): self { + $this->type = $type; + + return $this; + } + + /** + * @return string + */ + public function getType(): string { + return $this->type; + } + + + /** + * @param string $circleId + *-> + * + * @return Debug + */ + public function setCircleId(string $circleId): self { + $this->circleId = $circleId; + + return $this; + } + + /** + * @return string + */ + public function getCircleId(): string { + return $this->circleId; + } + + + /** + * @param string $instance + * + * @return Debug + */ + public function setInstance(string $instance): self { + $this->instance = $instance; + + return $this; + } + + /** + * @return string + */ + public function getInstance(): string { + return $this->instance; + } + + + /** + * @param ReferencedDataStore $debug + * + * @return Debug + */ + public function setDebug(ReferencedDataStore $debug): self { + $this->debug = $debug; + + return $this; + } + + /** + * @return ReferencedDataStore + */ + public function getDebug(): ReferencedDataStore { + return $this->debug; + } + + + /** + * @param int $time + * + * @return Debug + */ + public function setTime(int $time): self { + $this->time = $time; + + return $this; + } + + /** + * @return int + */ + public function getTime(): int { + return $this->time; + } + + + /** + * @param array $data + * + * @return IDeserializable + * @throws InvalidItemException + */ + public function import(array $data): IDeserializable { + $this->setThread($this->get('thread', $data)); + $this->setType($this->get('type', $data)); + $this->setCircleId($this->get('circleId', $data)); + $this->setInstance($this->get('instance', $data)); + $this->setTime($this->getInt('time', $data)); + + /** @var ReferencedDataStore $store */ + $store = $this->deserialize($this->getArray('debug', $data), ReferencedDataStore::class); + $this->setDebug($store); + + return $this; + } + + + /** + * @param array $data + * @param string $prefix + * + * @return IQueryRow + * @throws InvalidItemException + */ + public function importFromDatabase(array $data, string $prefix = ''): IQueryRow { + if (empty($this->getArray($prefix . 'debug', $data))) { + throw new InvalidItemException(); + } + + $this->setId($this->getInt($prefix . 'id', $data)); + $this->setThread($this->get($prefix . 'thread', $data)); + $this->setType($this->get($prefix . 'type', $data)); + $this->setCircleId($this->get($prefix . 'circle_id', $data)); + $this->setInstance($this->get($prefix . 'instance', $data)); + $this->setTime($this->getInt($prefix . 'time', $data)); + + /** @var ReferencedDataStore $store */ + $store = $this->deserialize($this->getArray('debug', $data), ReferencedDataStore::class); + $this->setDebug($store); + + return $this; + } + + + /** + * @return array + */ + public function jsonSerialize(): array { + return [ + 'thread' => $this->getThread(), + 'type' => $this->getType(), + 'circleId' => $this->getCircleId(), + 'instance' => $this->getInstance(), + 'debug' => $this->getDebug(), + 'time' => $this->getTime() + ]; + } +} diff --git a/lib/Model/Federated/FederatedEvent.php b/lib/Model/Federated/FederatedEvent.php index 8443f67c9..43639b999 100644 --- a/lib/Model/Federated/FederatedEvent.php +++ b/lib/Model/Federated/FederatedEvent.php @@ -31,19 +31,23 @@ namespace OCA\Circles\Model\Federated; -use OCA\Circles\Tools\Exceptions\InvalidItemException; -use OCA\Circles\Tools\Model\SimpleDataStore; -use OCA\Circles\Tools\Traits\TArrayTools; use JsonSerializable; use OCA\Circles\Model\Circle; use OCA\Circles\Model\Member; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IReferencedObject; +use OCA\Circles\Tools\Model\SimpleDataStore; +use OCA\Circles\Tools\Traits\TArrayTools; /** * Class FederatedEvent * * @package OCA\Circles\Model\Federated */ -class FederatedEvent implements JsonSerializable { +class FederatedEvent implements + IReferencedObject, + JsonSerializable { public const SEVERITY_LOW = 1; public const SEVERITY_HIGH = 3; @@ -65,6 +69,8 @@ class FederatedEvent implements JsonSerializable { /** @var Circle */ private $circle; + private ?SyncedItem $syncedItem = null; + /** @var string */ private $itemId = ''; @@ -137,11 +143,11 @@ public function getClass(): string { } /** - * @param mixed $class + * @param string $class * * @return self */ - public function setClass($class): self { + public function setClass(string $class): self { $this->class = $class; return $this; @@ -293,6 +299,31 @@ public function getCircle(): Circle { } + /** + * @param SyncedItem $syncedItem + * + * @return FederatedEvent + */ + public function setSyncedItem(SyncedItem $syncedItem): self { + $this->syncedItem = $syncedItem; + + return $this; + } + + /** + * @return SyncedItem + */ + public function getSyncedItem(): SyncedItem { + return $this->syncedItem; + } + + /** + * @return bool + */ + public function hasSyncedItem(): bool { + return !is_null($this->syncedItem); + } + /** * @param string $itemId * @@ -556,9 +587,7 @@ public function addResultEntry(string $key, array $result): self { * @return FederatedEvent */ public function bypass(int $flag): self { - if (!$this->canBypass($flag)) { - $this->bypass += $flag; - } + $this->bypass |= $flag; return $this; } @@ -602,6 +631,13 @@ public function import(array $data): self { $this->setMember($member); } + try { + $syncedItem = new SyncedItem(); + $syncedItem->import($this->getArray('syncedItem', $data)); + $this->setSyncedItem($syncedItem); + } catch (InvalidItemException $e) { + } + $members = []; foreach ($this->getArray('members', $data) as $item) { $member = new Member(); @@ -637,6 +673,9 @@ public function jsonSerialize(): array { if ($this->hasMember()) { $arr['member'] = $this->getMember(); } + if ($this->hasSyncedItem()) { + $arr['syncedItem'] = $this->getSyncedItem(); + } return $arr; } diff --git a/lib/Model/Federated/RemoteInstance.php b/lib/Model/Federated/RemoteInstance.php index 34eab92c1..d651ccb4d 100644 --- a/lib/Model/Federated/RemoteInstance.php +++ b/lib/Model/Federated/RemoteInstance.php @@ -31,12 +31,12 @@ namespace OCA\Circles\Model\Federated; -use OCA\Circles\Tools\Db\IQueryRow; -use OCA\Circles\Tools\Model\NCSignatory; -use OCA\Circles\Tools\Traits\TArrayTools; use JsonSerializable; use OCA\Circles\Exceptions\RemoteNotFoundException; use OCA\Circles\Exceptions\RemoteUidException; +use OCA\Circles\Tools\Db\IQueryRow; +use OCA\Circles\Tools\Model\NCSignatory; +use OCA\Circles\Tools\Traits\TArrayTools; /** * Class AppService @@ -73,6 +73,9 @@ class RemoteInstance extends NCSignatory implements IQueryRow, JsonSerializable public const INHERITED = 'inherited'; public const UID = 'uid'; public const AUTH_SIGNED = 'auth-signed'; + public const DEBUG = 'debug'; + public const SYNC_ITEM = 'syncItem'; + public const SYNC_SHARE = 'syncShare'; /** @var int */ private $dbId = 0; @@ -125,6 +128,10 @@ class RemoteInstance extends NCSignatory implements IQueryRow, JsonSerializable /** @var bool */ private $identityAuthed = false; + private string $syncItem = ''; + private string $syncShare = ''; + private string $debug = ''; + /** * @param int $dbId @@ -277,7 +284,6 @@ public function getTest(): string { return $this->test; } - /** * @return string */ @@ -473,6 +479,59 @@ public function mustBeIdentityAuthed(): void { } + /** + * @param string $syncItem + */ + public function setSyncItem(string $syncItem): self { + $this->syncItem = $syncItem; + + return $this; + } + + /** + * @return string + */ + public function getSyncItem(): string { + return $this->syncItem; + } + + + /** + * @param string $syncShare + */ + public function setSyncShare(string $syncShare): self { + $this->syncShare = $syncShare; + + return $this; + } + + /** + * @return string + */ + public function getSyncShare(): string { + return $this->syncShare; + } + + + /** + * @param string $debug + * + * @return RemoteInstance + */ + public function setDebug(string $debug): self { + $this->debug = $debug; + + return $this; + } + + /** + * @return string + */ + public function getDebug(): string { + return $this->debug; + } + + /** * @param array $data * @@ -492,6 +551,9 @@ public function import(array $data): NCSignatory { ->setMember($this->get(self::MEMBER, $data)) ->setInherited($this->get(self::INHERITED, $data)) ->setMemberships($this->get(self::MEMBERSHIPS, $data)) + ->setDebug($this->get(self::DEBUG, $data)) + ->setSyncItem($this->get(self::SYNC_ITEM, $data)) + ->setSyncShare($this->get(self::SYNC_SHARE, $data)) ->setUid($this->get(self::UID, $data)); $algo = ''; @@ -522,7 +584,10 @@ public function jsonSerialize(): array { self::MEMBERS => $this->getMembers(), self::MEMBER => $this->getMember(), self::INHERITED => $this->getInherited(), - self::MEMBERSHIPS => $this->getMemberships() + self::MEMBERSHIPS => $this->getMemberships(), + self::SYNC_ITEM => $this->getSyncItem(), + self::SYNC_SHARE => $this->getSyncShare(), + self::DEBUG => $this->getDebug(), ]; if ($this->getAuthSigned() !== '') { diff --git a/lib/Model/Member.php b/lib/Model/Member.php index 4dd420b83..f43fe9ff9 100644 --- a/lib/Model/Member.php +++ b/lib/Model/Member.php @@ -46,6 +46,7 @@ use OCA\Circles\Tools\Db\IQueryRow; use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; use OCA\Circles\Tools\Traits\TArrayTools; use OCA\Circles\Tools\Traits\TDeserialize; @@ -57,7 +58,7 @@ class Member extends ManagedModel implements IEntity, IFederatedUser, - IDeserializable, + IReferencedObject, IQueryRow, JsonSerializable { use TArrayTools; @@ -741,7 +742,7 @@ public function getLink(string $singleId, bool $detailed = false): Membership { if ($singleId !== '') { $this->getManager()->getLink($this, $singleId, $detailed); } - + throw new MembershipNotFoundException(); } diff --git a/lib/Model/SyncedItem.php b/lib/Model/SyncedItem.php new file mode 100644 index 000000000..34e878e3c --- /dev/null +++ b/lib/Model/SyncedItem.php @@ -0,0 +1,331 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Model; + +use JsonSerializable; +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\IFederatedModel; +use OCA\Circles\Tools\Db\IQueryRow; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; +use OCA\Circles\Tools\Traits\TArrayTools; + +class SyncedItem extends ManagedModel implements IFederatedModel, IReferencedObject, IQueryRow, JsonSerializable { + use TArrayTools; + + private int $id; + private string $singleId; + private string $instance = ''; + private string $appId; + private string $itemType; + private string $itemId; + private string $checksum = ''; + private array $serialized = []; + private bool $deleted = false; + + public function __construct() { + } + + + /** + * @param int $id + * + * @return SyncedItem + */ + public function setId(int $id): self { + $this->id = $id; + + return $this; + } + + /** + * @return int + */ + public function getId(): int { + return $this->id; + } + + + /** + * @param string $singleId + * + * @return SyncedItem + */ + public function setSingleId(string $singleId): self { + $this->singleId = $singleId; + + return $this; + } + + /** + * @return string + */ + public function getSingleId(): string { + return $this->singleId; + } + + + /** + * @param string $instance + * + * @return SyncedItem + */ + public function setInstance(string $instance): self { + $this->instance = $instance; + + return $this; + } + + /** + * @return string + */ + public function getInstance(): string { + return $this->instance; + } + + /** + * @return bool + */ + public function isLocal(): bool { + return $this->getManager()->isLocalInstance($this->getInstance()); + } + + + /** + * @param string $appId + * + * @return SyncedItem + */ + public function setAppId(string $appId): self { + $this->appId = $appId; + + return $this; + } + + /** + * @return string + */ + public function getAppId(): string { + return $this->appId; + } + + + /** + * @param string $itemType + * + * @return SyncedItem + */ + public function setItemType(string $itemType): self { + $this->itemType = $itemType; + + return $this; + } + + /** + * @return string + */ + public function getItemType(): string { + return $this->itemType; + } + + + /** + * @param string $itemId + * + * @return SyncedItem + */ + public function setItemId(string $itemId): self { + $this->itemId = $itemId; + + return $this; + } + + /** + * @param int $itemId + * + * @return SyncedItem + */ + public function setItemIdAsInt(int $itemId): self { + $this->itemId = (string)$itemId; + + return $this; + } + + /** + * @return string + */ + public function getItemId(): string { + return $this->itemId; + } + + /** + * @return int + */ + public function getItemIdAsInt(): int { + return (int)$this->itemId; + } + + /** + * @param string $checksum + * + * @return SyncedItem + */ + public function setChecksum(string $checksum): self { + $this->checksum = $checksum; + + return $this; + } + + /** + * @return string + */ + public function getChecksum(): string { + return $this->checksum; + } + + + /** + * @param array $serialized + * + * @return SyncedItem + */ + public function setSerialized(array $serialized): self { + $this->serialized = $serialized; + + return $this; + } + + /** + * @return array + */ + public function getSerialized(): array { + return $this->serialized; + } + + + /** + * @param bool $deleted + */ + public function setDeleted(bool $deleted): void { + $this->deleted = $deleted; + } + + /** + * @return bool + */ + public function isDeleted(): bool { + return $this->deleted; + } + + + /** + * @param array $data + * + * @return ShareToken + * @throws InvalidItemException + */ + public function import(array $data): IDeserializable { + if ($this->get('singleId', $data) === 0) { + throw new InvalidItemException(); + } + + $this->setSingleId($this->get('singleId', $data)); + $this->setInstance($this->get('instance', $data)); + $this->setAppId($this->get('appId', $data)); + $this->setItemType($this->get('itemType', $data)); + $this->setItemId($this->get('itemId', $data)); + $this->setChecksum($this->get('checksum', $data)); + $this->setSerialized($this->getArray('serializedData', $data)); + $this->setDeleted($this->getBool('deleted', $data)); + + return $this; + } + + + /** + * @param array $data + * @param string $prefix + * + * @return IQueryRow + * @throws SyncedItemNotFoundException + */ + public function importFromDatabase(array $data, string $prefix = ''): IQueryRow { + if ($this->get($prefix . 'single_id', $data) === '') { + throw new SyncedItemNotFoundException(); + } + + $this->setSingleId($this->get($prefix . 'single_id', $data)); + $this->setInstance($this->get($prefix . 'instance', $data)); + $this->setInstance($this->get($prefix . 'instance', $data)); + $this->setAppId($this->get($prefix . 'app_id', $data)); + $this->setItemType($this->get($prefix . 'item_type', $data)); + $this->setItemId($this->get($prefix . 'item_id', $data)); + $this->setChecksum($this->get($prefix . 'checksum', $data)); + $this->setDeleted($this->getBool($prefix . 'deleted', $data)); + + if ($this->getInstance() === '') { + $this->setInstance($this->getManager()->getLocalInstance()); + } + + return $this; + } + + /** + * @return array + */ + public function jsonSerialize(): array { + return [ + 'singleId' => $this->getSingleId(), + 'instance' => $this->getInstance(), + 'appId' => $this->getAppId(), + 'itemType' => $this->getItemType(), + 'itemId' => $this->getItemId(), + 'checksum' => $this->getChecksum(), + 'serializedData' => $this->getSerialized(), + 'deleted' => $this->isDeleted() + ]; + } + + + /** + * @param SyncedItem $item + * + * @return bool + */ + public function compareWith(SyncedItem $item): bool { + return !($this->getSingleId() !== $item->getSingleId() + || $this->getAppId() !== $item->getAppId() + || $this->getItemType() !== $item->getItemType() + || $this->getItemId() !== $item->getItemId()); + } +} diff --git a/lib/Model/SyncedItemLock.php b/lib/Model/SyncedItemLock.php new file mode 100644 index 000000000..47f8ff045 --- /dev/null +++ b/lib/Model/SyncedItemLock.php @@ -0,0 +1,228 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Model; + +use JsonSerializable; +use OCA\Circles\Exceptions\ShareTokenNotFoundException; +use OCA\Circles\Tools\Db\IQueryRow; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\Traits\TArrayTools; + +class SyncedItemLock implements IDeserializable, IQueryRow, JsonSerializable { + use TArrayTools; + + private int $id; + private string $singleId; + private string $updateType; + private string $updateTypeId; + private int $time; + private bool $verifyChecksum; + + + public function __construct( + string $updateType = '', + string $updateTypeId = '', + bool $verifyChecksum = false + ) { + $this->updateType = $updateType; + $this->updateTypeId = $updateTypeId; + $this->verifyChecksum = $verifyChecksum; + } + + + /** + * @param int $id + * + * @return SyncedItemLock + */ + public function setId(int $id): self { + $this->id = $id; + + return $this; + } + + /** + * @return int + */ + public function getId(): int { + return $this->id; + } + + + /** + * @param string $singleId + * + * @return SyncedItemLock + */ + public function setSingleId(string $singleId): self { + $this->singleId = $singleId; + + return $this; + } + + /** + * @return string + */ + public function getSingleId(): string { + return $this->singleId; + } + + /** + * @param string $updateType + * + * @return SyncedItemLock + */ + public function setUpdateType(string $updateType): self { + $this->updateType = $updateType; + + return $this; + } + + /** + * @return string + */ + public function getUpdateType(): string { + return $this->updateType; + } + + + /** + * @param string $updateTypeId + * + * @return SyncedItemLock + */ + public function setUpdateTypeId(string $updateTypeId): self { + $this->updateTypeId = $updateTypeId; + + return $this; + } + + /** + * @return string + */ + public function getUpdateTypeId(): string { + return $this->updateTypeId; + } + + + /** + * @param int $time + * + * @return SyncedItemLock + */ + public function setTime(int $time): self { + $this->time = $time; + + return $this; + } + + /** + * @return int + */ + public function getTime(): int { + return $this->time; + } + + + /** + * @param bool $verifyChecksum + * + * @return SyncedItemLock + */ + public function setVerifyChecksum(bool $verifyChecksum): self { + $this->verifyChecksum = $verifyChecksum; + + return $this; + } + + /** + * @return bool + */ + public function isVerifyChecksum(): bool { + return $this->verifyChecksum; + } + + + /** + * @param array $data + * + * @return ShareToken + * @throws InvalidItemException + */ + public function import(array $data): IDeserializable { + if ($this->getInt('singleId', $data) === 0) { + throw new InvalidItemException(); + } + + $this->setSingleId($this->get('singleId', $data)); + $this->setUpdateType($this->get('updateType', $data)); + $this->setUpdateTypeId($this->get('updateTypeId', $data)); + $this->setTime($this->getInt('time', $data)); + + return $this; + } + + + /** + * @param array $data + * @param string $prefix + * + * @return IQueryRow + * @throws ShareTokenNotFoundException + */ + public function importFromDatabase(array $data, string $prefix = ''): IQueryRow { + if ($this->get($prefix . 'token', $data) === '') { + throw new ShareTokenNotFoundException(); + } + + $this->setSingleId($this->get($prefix . 'single_id', $data)); + $this->setUpdateType($this->get($prefix . 'update_type', $data)); + $this->setUpdateTypeId($this->get($prefix . 'update_type_id', $data)); + $this->setTime($this->getInt($prefix . 'time', $data)); + + return $this; + } + + /** + * @return array + */ + public function jsonSerialize(): array { + return [ + 'singleId' => $this->getSingleId(), + 'updateType' => $this->getUpdateType(), + 'updateTypeId' => $this->getUpdateTypeId(), + 'time' => $this->getTime(), + 'verifyChecksum' => $this->isVerifyChecksum() + ]; + } +} diff --git a/lib/Model/SyncedShare.php b/lib/Model/SyncedShare.php new file mode 100644 index 000000000..8c2e7afef --- /dev/null +++ b/lib/Model/SyncedShare.php @@ -0,0 +1,154 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Model; + +use JsonSerializable; +use OCA\Circles\Exceptions\SyncedShareNotFoundException; +use OCA\Circles\Tools\Db\IQueryRow; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; +use OCA\Circles\Tools\Traits\TArrayTools; + +class SyncedShare implements IReferencedObject, IQueryRow, JsonSerializable { + use TArrayTools; + + private int $id; + private string $singleId; + private string $circleId; + + public function __construct() { + } + + + /** + * @param int $id + * + * @return SyncedShare + */ + public function setId(int $id): self { + $this->id = $id; + + return $this; + } + + /** + * @return int + */ + public function getId(): int { + return $this->id; + } + + + /** + * @param string $singleId + * + * @return SyncedShare + */ + public function setSingleId(string $singleId): self { + $this->singleId = $singleId; + + return $this; + } + + /** + * @return string + */ + public function getSingleId(): string { + return $this->singleId; + } + + /** + * @param string $circleId + * + * @return SyncedShare + */ + public function setCircleId(string $circleId): self { + $this->circleId = $circleId; + + return $this; + } + + /** + * @return string + */ + public function getCircleId(): string { + return $this->circleId; + } + + + /** + * @param array $data + * + * @return ShareToken + * @throws InvalidItemException + */ + public function import(array $data): IDeserializable { + if ($this->getInt('singleId', $data) === 0) { + throw new InvalidItemException(); + } + + $this->setSingleId($this->get('singleId', $data)); + $this->setCircleId($this->get('circleId', $data)); + + return $this; + } + + + /** + * @param array $data + * @param string $prefix + * + * @return IQueryRow + * @throws SyncedShareNotFoundException + */ + public function importFromDatabase(array $data, string $prefix = ''): IQueryRow { + if ($this->get($prefix . 'single_id', $data) === '') { + throw new SyncedShareNotFoundException(); + } + + $this->setCircleId($this->get($prefix . 'circle_id', $data)); + $this->setSingleId($this->get($prefix . 'single_id', $data)); + + return $this; + } + + /** + * @return array + */ + public function jsonSerialize(): array { + return [ + 'singleId' => $this->getSingleId(), + 'circleId' => $this->getCircleId() + ]; + } +} diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php index 649c4c305..5947d711e 100644 --- a/lib/Service/ConfigService.php +++ b/lib/Service/ConfigService.php @@ -118,6 +118,7 @@ class ConfigService { public const MAINTENANCE_UPDATE = 'maintenance_update'; public const MAINTENANCE_RUN = 'maintenance_run'; + public const DEBUG = 'debug'; public const GS_MODE = 'mode'; public const GS_KEY = 'key'; @@ -198,6 +199,8 @@ class ConfigService { self::MAINTENANCE_UPDATE => '[]', self::MAINTENANCE_RUN => '0', + self::DEBUG => '', + self::FORCE_NC_BASE => '', self::TEST_NC_BASE => '', self::CIRCLES_CONTACT_BACKEND => '0', diff --git a/lib/Service/DebugService.php b/lib/Service/DebugService.php new file mode 100644 index 000000000..a8a88ba2a --- /dev/null +++ b/lib/Service/DebugService.php @@ -0,0 +1,229 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Service; + +use Exception; +use JsonSerializable; +use OCA\Circles\Db\DebugRequest; +use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\Exceptions\RemoteInstanceException; +use OCA\Circles\Exceptions\RemoteNotFoundException; +use OCA\Circles\Exceptions\RemoteResourceNotFoundException; +use OCA\Circles\Exceptions\UnknownRemoteException; +use OCA\Circles\Model\Debug; +use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IReferencedObject; +use OCA\Circles\Tools\Model\ReferencedDataStore; +use OCA\Circles\Tools\Model\Request; +use OCA\Circles\Tools\Traits\TStringTools; +use Psr\Log\LoggerInterface; + +class DebugService { + use TStringTools; + + public const ACTION = '_action'; + public const EXCEPTION = '_exception'; + public const E_CLASS = '_class'; + public const E_TRACE = '_trace'; + + const DEBUG_LOCAL = 'local'; + const DEBUG_DAEMON = 'daemon'; + + + private LoggerInterface $loggerInterface; + private DebugRequest $debugRequest; + private RemoteStreamService $remoteStreamService; + private ConfigService $configService; + + private string $debugType; + private string $processToken; + + /** + * @param DebugRequest $debugRequest + * @param RemoteStreamService $remoteStreamService + * @param ConfigService $configService + */ + public function __construct( + LoggerInterface $loggerInterface, + DebugRequest $debugRequest, + RemoteStreamService $remoteStreamService, + ConfigService $configService + ) { + $this->loggerInterface = $loggerInterface; + $this->debugRequest = $debugRequest; + $this->remoteStreamService = $remoteStreamService; + $this->configService = $configService; + + $this->processToken = $this->token(7); + $this->debugType = ''; + } + + + public function setDebugType(string $type): void { + $this->debugType = $type; + } + + /** + * @param int $history + * + * @return Debug[] + */ + public function getHistory(int $history): array { + return $this->debugRequest->getHistory($history); + } + + /** + * @param int $lastId + * + * @return Debug[] + */ + public function getSince(int $lastId): array { + return $this->debugRequest->getSince($lastId); + } + + + /** + * @param string $action + * @param string $circleId + * @param array $objects + */ + public function info(string $action, string $circleId = '', array $objects = []): void { + if (!$this->isDebugEnabled()) { + return; + } + + $store = new ReferencedDataStore(); + $store->s(self::ACTION, $action); + + try { + $this->store($store, $circleId, $objects); + } catch (Exception $e) { + //$this->logger-> + } + } + + + /** + * @param Exception $e + * @param string $circleId + * @param array $objects + */ + public function exception(Exception $e, string $circleId = '', array $objects = []): void { + if (!$this->isDebugEnabled()) { + return; + } + + $msg = $e->getMessage(); + $store = new ReferencedDataStore(); + $store->s(self::ACTION, '{?' . self::E_CLASS . '}' . (($msg !== '') ? ' (' . $msg . ')' : '')); + $store->s(self::E_CLASS, get_class($e)); + $store->s(self::EXCEPTION, $e->getMessage()); + $store->sArray(self::E_TRACE, debug_backtrace()); + + try { + $this->store($store, $circleId, $objects); + } catch (Exception $e) { + //$this->logger-> + } + } + + + /** + * @param ReferencedDataStore $store + * @param string $circleId + * @param array $objects + * + * @throws FederatedItemException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws UnknownRemoteException + */ + private function store(ReferencedDataStore $store, string $circleId, array $objects = []): void { + foreach ($objects as $k => $obj) { + try { + $store->sMixed((string)$k, $obj); + } catch (InvalidItemException $e) { + } + } + + $debug = new Debug($store, $circleId, $this->processToken, $this->debugType); + if ($this->isDebugLocal()) { + $this->save($debug); + + return; + } + + $this->remote($debug); + } + + /** + * @param Debug $debug + */ + public function save(Debug $debug): void { + $this->debugRequest->save($debug); + } + + /** + * @param Debug $debug + * + * @throws FederatedItemException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws UnknownRemoteException + */ + private function remote(Debug $debug): void { + $this->remoteStreamService->resultRequestRemoteInstance( + $this->getDebugInstance(), + RemoteInstance::DEBUG, + Request::TYPE_POST, + $debug, + ); + } + + + private function isDebugEnabled(): bool { + return ($this->configService->getAppValue(ConfigService::DEBUG) !== ''); + } + + private function isDebugLocal(): bool { + return ($this->configService->getAppValue(ConfigService::DEBUG) === self::DEBUG_LOCAL + || $this->configService->getAppValue(ConfigService::DEBUG) === self::DEBUG_DAEMON); + } + + private function getDebugInstance(): string { + return $this->configService->getAppValue(ConfigService::DEBUG); + } + +} diff --git a/lib/Service/FederatedEventService.php b/lib/Service/FederatedEventService.php index 9759da74c..a715a6a6e 100644 --- a/lib/Service/FederatedEventService.php +++ b/lib/Service/FederatedEventService.php @@ -34,11 +34,8 @@ use OCA\Circles\Db\EventWrapperRequest; use OCA\Circles\Db\MemberRequest; use OCA\Circles\Db\RemoteRequest; -use OCA\Circles\Db\ShareLockRequest; use OCA\Circles\Exceptions\FederatedEventException; use OCA\Circles\Exceptions\FederatedItemException; -use OCA\Circles\Exceptions\FederatedShareBelongingException; -use OCA\Circles\Exceptions\FederatedShareNotFoundException; use OCA\Circles\Exceptions\InitiatorNotConfirmedException; use OCA\Circles\Exceptions\OwnerNotFoundException; use OCA\Circles\Exceptions\RemoteInstanceException; @@ -53,14 +50,14 @@ use OCA\Circles\IFederatedItemHighSeverity; use OCA\Circles\IFederatedItemInitiatorCheckNotRequired; use OCA\Circles\IFederatedItemInitiatorMembershipNotRequired; -use OCA\Circles\IFederatedItemLimitedToInstanceWithMembership; +use OCA\Circles\IFederatedItemLimitedToInstanceWithMember; use OCA\Circles\IFederatedItemLoopbackTest; use OCA\Circles\IFederatedItemMemberCheckNotRequired; use OCA\Circles\IFederatedItemMemberEmpty; use OCA\Circles\IFederatedItemMemberOptional; use OCA\Circles\IFederatedItemMemberRequired; use OCA\Circles\IFederatedItemMustBeInitializedLocally; -use OCA\Circles\IFederatedItemSharedItem; +use OCA\Circles\IFederatedItemSyncedItem; use OCA\Circles\Model\Circle; use OCA\Circles\Model\Federated\EventWrapper; use OCA\Circles\Model\Federated\FederatedEvent; @@ -91,9 +88,6 @@ class FederatedEventService extends NCSignature { /** @var RemoteRequest */ private $remoteRequest; - /** @var ShareLockRequest */ - private $shareLockRequest; - /** @var MemberRequest */ private $memberRequest; @@ -106,6 +100,8 @@ class FederatedEventService extends NCSignature { /** @var ConfigService */ private $configService; + private DebugService $debugService; + /** * FederatedEventService constructor. @@ -113,27 +109,27 @@ class FederatedEventService extends NCSignature { * @param EventWrapperRequest $eventWrapperRequest * @param RemoteRequest $remoteRequest * @param MemberRequest $memberRequest - * @param ShareLockRequest $shareLockRequest * @param RemoteUpstreamService $remoteUpstreamService * @param InterfaceService $interfaceService * @param ConfigService $configService + * @param DebugService $debugService */ public function __construct( EventWrapperRequest $eventWrapperRequest, RemoteRequest $remoteRequest, MemberRequest $memberRequest, - ShareLockRequest $shareLockRequest, RemoteUpstreamService $remoteUpstreamService, InterfaceService $interfaceService, - ConfigService $configService + ConfigService $configService, + DebugService $debugService ) { $this->eventWrapperRequest = $eventWrapperRequest; $this->remoteRequest = $remoteRequest; - $this->shareLockRequest = $shareLockRequest; $this->memberRequest = $memberRequest; $this->remoteUpstreamService = $remoteUpstreamService; $this->interfaceService = $interfaceService; $this->configService = $configService; + $this->debugService = $debugService; } @@ -168,6 +164,17 @@ public function newEvent(FederatedEvent $event): array { } if ($this->configService->isLocalInstance($instance)) { + + $this->debugService->info( + 'New local event ', + ($event->hasCircle()) ? $event->getCircle()->getSingleId() : '', + [ + 'event' => $event, + 'federatedItem' => $federatedItem, + 'instance' => $instance + ] + ); + $event->setSender($instance); $federatedItem->verify($event); @@ -181,6 +188,23 @@ public function newEvent(FederatedEvent $event): array { $this->initBroadcast($event); } else { +// $this->debugService->info( +// 'Requesting {event.instance} to confirm IFederatedEvent {event.getClass}', +// $circle->getSingleId(), +// [ +// 'event' => $event +// ] +// ); + + $this->debugService->info( + 'sending {`IFederatedEvent} {event.class} to master {instance} for confirmation', + ($event->hasCircle()) ? $event->getCircle()->getSingleId() : '', + [ + 'event' => $event, + 'instance' => $instance + ] + ); + $this->remoteUpstreamService->confirmEvent($event); if ($event->isDataRequestOnly()) { return $event->getOutcome(); @@ -266,8 +290,6 @@ public function getFederatedItem(FederatedEvent $event, bool $checkLocalOnly = t $this->confirmRequiredCondition($event, $item, $checkLocalOnly); $this->configureEvent($event, $item); -// $this->confirmSharedItem($event, $item); - return $item; } @@ -334,32 +356,9 @@ private function confirmRequiredCondition( if ($item instanceof IFederatedItemMustBeInitializedLocally && $checkLocalOnly) { throw new FederatedEventException('FederatedItem must be executed locally'); } - } - - /** - * @param FederatedEvent $event - * @param IFederatedItem $item - * - * @throws FederatedEventException - * @throws FederatedShareBelongingException - * @throws FederatedShareNotFoundException - * @throws OwnerNotFoundException - */ - private function confirmSharedItem(FederatedEvent $event, IFederatedItem $item): void { - if (!$item instanceof IFederatedItemSharedItem) { - return; - } - - if ($event->getItemId() === '') { - throw new FederatedEventException('FederatedItem must contains ItemId'); - } - - if ($this->configService->isLocalInstance($event->getCircle()->getInstance())) { - $shareLock = $this->shareLockRequest->getShare($event->getItemId()); - if ($shareLock->getInstance() !== $event->getSender()) { - throw new FederatedShareBelongingException('ShareLock belongs to another instance'); - } + if ($item instanceof IFederatedItemSyncedItem && !$event->hasSyncedItem()) { + throw new FederatedEventException('FederatedItem must contains a valid SyncedItem'); } } @@ -372,7 +371,7 @@ private function configureEvent(FederatedEvent $event, IFederatedItem $item) { if ($item instanceof IFederatedItemAsyncProcess) { $event->setAsync(true); } - if ($item instanceof IFederatedItemLimitedToInstanceWithMembership) { + if ($item instanceof IFederatedItemLimitedToInstanceWithMember) { $event->setLimitedToInstanceWithMember(true); } if ($item instanceof IFederatedItemDataRequestOnly) { diff --git a/lib/Service/FederatedShareService.php b/lib/Service/FederatedShareService.php deleted file mode 100644 index 5ed5afa2e..000000000 --- a/lib/Service/FederatedShareService.php +++ /dev/null @@ -1,117 +0,0 @@ - - * @copyright 2021 - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -namespace OCA\Circles\Service; - -use OCA\Circles\Exceptions\CircleNotFoundException; -use OCA\Circles\Exceptions\FederatedEventDSyncException; -use OCA\Circles\Exceptions\FederatedEventException; -use OCA\Circles\Exceptions\FederatedItemException; -use OCA\Circles\Exceptions\FederatedShareAlreadyLockedException; -use OCA\Circles\Exceptions\InitiatorNotConfirmedException; -use OCA\Circles\Exceptions\InitiatorNotFoundException; -use OCA\Circles\Exceptions\OwnerNotFoundException; -use OCA\Circles\Exceptions\RemoteNotFoundException; -use OCA\Circles\Exceptions\RemoteResourceNotFoundException; -use OCA\Circles\Exceptions\UnknownRemoteException; -use OCA\Circles\FederatedItems\ItemLock; -use OCA\Circles\Model\Federated\FederatedEvent; -use OCA\Circles\Model\Federated\FederatedShare; -use OCA\Circles\Tools\ActivityPub\NCSignature; -use OCA\Circles\Tools\Exceptions\InvalidItemException; -use OCA\Circles\Tools\Exceptions\RequestNetworkException; -use OCA\Circles\Tools\Exceptions\SignatoryException; -use OCA\Circles\Tools\Exceptions\UnknownTypeException; - -/** - * Class FederatedShareService - * - * @package OCA\Circles\Service - */ -class FederatedShareService extends NCSignature { - - - /** @var FederatedEventService */ - private $federatedEventService; - - /** @var CircleService */ - private $circleService; - - - /** - * FederatedEventService constructor. - * - * @param FederatedEventService $federatedEventService - * @param CircleService $circleService - */ - public function __construct(FederatedEventService $federatedEventService, CircleService $circleService) { - $this->federatedEventService = $federatedEventService; - $this->circleService = $circleService; - } - - - /** - * @param string $circleId - * @param string $itemId - * - * @return FederatedShare - * @throws FederatedEventDSyncException - * @throws FederatedEventException - * @throws FederatedItemException - * @throws FederatedShareAlreadyLockedException - * @throws InitiatorNotConfirmedException - * @throws InvalidItemException - * @throws OwnerNotFoundException - * @throws RemoteNotFoundException - * @throws RemoteResourceNotFoundException - * @throws RequestNetworkException - * @throws SignatoryException - * @throws UnknownRemoteException - * @throws UnknownTypeException - * @throws CircleNotFoundException - * @throws InitiatorNotFoundException - */ - public function lockItem(string $circleId, string $itemId): FederatedShare { - $circle = $this->circleService->getCircle($circleId); - - $event = new FederatedEvent(ItemLock::class); - $event->setCircle($circle); - $event->getData()->s('itemId', $itemId); - $data = $this->federatedEventService->newEvent($event); - - /** @var FederatedShare $share */ - $share = $data->gObj('federatedShare', FederatedShare::class); - if ($share->getLockStatus() === ItemLock::STATUS_INSTANCE_LOCKED) { - throw new FederatedShareAlreadyLockedException('item already locked by ' . $share->getInstance()); - } - - return $share; - } -} diff --git a/lib/Service/FederatedSyncItemService.php b/lib/Service/FederatedSyncItemService.php new file mode 100644 index 000000000..fa6170956 --- /dev/null +++ b/lib/Service/FederatedSyncItemService.php @@ -0,0 +1,339 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Service; + +use Exception; +use OCA\Circles\Db\RemoteRequest; +use OCA\Circles\Db\SyncedItemRequest; +use OCA\Circles\Db\SyncedShareRequest; +use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\Exceptions\FederatedSyncConflictException; +use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; +use OCA\Circles\Exceptions\InvalidIdException; +use OCA\Circles\Exceptions\RemoteInstanceException; +use OCA\Circles\Exceptions\RemoteNotFoundException; +use OCA\Circles\Exceptions\RemoteResourceNotFoundException; +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\Exceptions\UnknownRemoteException; +use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Tools\ActivityPub\NCSignature; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Model\Request; +use OCA\Circles\Tools\Traits\TDeserialize; +use OCA\Circles\Tools\Traits\TStringTools; + +class FederatedSyncItemService extends NCSignature { + use TStringTools; + use TDeserialize; + + private SyncedItemRequest $syncedItemRequest; + private SyncedShareRequest $syncedShareRequest; + private RemoteRequest $remoteRequest; + private FederatedSyncService $federatedSyncService; + private FederatedEventService $federatedEventService; + private RemoteStreamService $remoteStreamService; + private InterfaceService $interfaceService; + private DebugService $debugService; + + + /** + * @param SyncedItemRequest $syncedItemRequest + * @param SyncedShareRequest $syncedShareRequest + * @param RemoteRequest $remoteRequest + * @param FederatedSyncService $federatedSyncService + * @param FederatedEventService $federatedEventService + * @param RemoteStreamService $remoteStreamService + * @param InterfaceService $interfaceService + * @param DebugService $debugService + */ + public function __construct( + SyncedItemRequest $syncedItemRequest, + SyncedShareRequest $syncedShareRequest, + RemoteRequest $remoteRequest, + FederatedSyncService $federatedSyncService, + FederatedEventService $federatedEventService, + RemoteStreamService $remoteStreamService, + InterfaceService $interfaceService, + DebugService $debugService + ) { + $this->syncedItemRequest = $syncedItemRequest; + $this->syncedShareRequest = $syncedShareRequest; + $this->remoteRequest = $remoteRequest; + $this->federatedSyncService = $federatedSyncService; + $this->federatedEventService = $federatedEventService; + $this->remoteStreamService = $remoteStreamService; + $this->interfaceService = $interfaceService; + $this->debugService = $debugService; + } + + + /** + * @param SyncedItem $syncedItem + * + * @return SyncedItem + * @throws FederatedItemException + * @throws FederatedSyncConflictException + * @throws InvalidItemException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws UnknownRemoteException + */ + public function confirmRemoteSyncedItem(SyncedItem $syncedItem): SyncedItem { + if ($syncedItem->isLocal()) { + // TODO: how is it really handle ? + throw new FederatedSyncConflictException('instance of SyncedItem is set as local'); + } + + $this->interfaceService->setCurrentInterfaceFromInstance($syncedItem->getInstance()); + $data = $this->remoteStreamService->resultRequestRemoteInstance( + $syncedItem->getInstance(), + RemoteInstance::SYNC_ITEM, + Request::TYPE_GET, + $syncedItem + ); + + /** @var SyncedItem $remoteItem */ + $remoteItem = $this->deserialize($data, SyncedItem::class); + + if (!$syncedItem->compareWith($remoteItem)) { + // TODO: how is it really handle ? + throw new FederatedSyncConflictException('returned data from remote instance does not fit'); + } + + $this->debugService->info( + 'data from SyncedItem {syncedItem.singleId} retrieved from {syncedItem.instance} with Checksum {remoteItem.checksum}', + '', + [ + 'data' => $data, + 'syncedItem' => $syncedItem, + 'remoteItem' => $remoteItem + ] + ); + + return $remoteItem; + } + + + /** + * TODO: $serializeItem might not be a necessary check + * + * @param string $singleId + * @param bool $serializeItem + * + * @return SyncedItem + * @throws FederatedSyncConflictException + * @throws FederatedSyncManagerNotFoundException + * @throws SyncedItemNotFoundException + */ + public function getLocalSyncedItem(string $singleId, bool $serializeItem = false): SyncedItem { + $item = $this->syncedItemRequest->getSyncedItemFromSingleId($singleId); + if (!$item->isLocal()) { + throw new FederatedSyncConflictException(); + } + + if ($serializeItem) { + $item->setSerialized( + $this->federatedSyncService->initSyncManager($item) + ->serializeItem($item->getItemId()) + ); + } + + return $item; + } + + + /** + * get existing SyncedItem based appId, itemType and itemId. + * + * throws FederatedSyncConflictException if sync conflict: + * - item is marked as deleted, but app have not confirmed its deletion, + * - item is not local and have no known origin. + * + * if SyncedItem does not exist, app is called to confirm itemId exist locally. If item exists, we create + * a new SyncedItem. + * + * @param string $appId + * @param string $itemType + * @param string $itemId + * + * @return SyncedItem + * @throws FederatedSyncConflictException + * @throws FederatedSyncManagerNotFoundException + */ + public function getSyncedItem(string $appId, string $itemType, string $itemId): SyncedItem { + + // verify existing SyncedItem is not flag as deleted + try { + $syncedItem = $this->syncedItemRequest->getSyncedItem($appId, $itemType, $itemId); + if ($syncedItem->isDeleted()) { + throw new FederatedSyncConflictException("SyncedItem $appId.$itemType.$itemId is deprecated"); + } + + $this->debugService->info('Found SyncedItem {syncedItem.singleId} in database', '', [ + 'syncedItem' => $syncedItem + ]); + + return $syncedItem; + } catch (SyncedItemNotFoundException $e) { + } + + $syncManager = $this->federatedSyncService->getSyncManager($appId, $itemType); + $this->debugService->info( + 'SyncedItem is unknown, calling {`serializeItem()} on {syncManager.class} to confirm item {itemId} is local', + '', + [ + 'syncManager' => get_class($syncManager), + 'itemId' => $itemId + ] + ); + try { + $syncManager->serializeItem($itemId); + } catch (Exception $e) { + throw new FederatedSyncConflictException( + 'SyncedItem not found in database and does not appears to be local' + ); + } + + // create entry + return $this->createSyncedItem($appId, $itemType, $itemId); + } + + + /** + * create a new (local) SyncedItem based on appId, itemType, itemId. + * + * @param string $appId + * @param string $itemType + * @param string $itemId + * + * @return SyncedItem + */ + private function createSyncedItem(string $appId, string $itemType, string $itemId): SyncedItem { + $syncedItem = new SyncedItem(); + $syncedItem->setSingleId($this->token(31)) + ->setAppId($appId) + ->setItemType($itemType) + ->setItemId($itemId); + + $this->debugService->info( + 'generating new SyncedItem for {syncedItem.appId}.{syncedItem.itemType}.{syncedItem.itemId}', + '', + ['syncedItem' => $syncedItem] + ); + + return $syncedItem; + } + + + /** + * TODO: verify Exception returned and how to handle them (remove entry ? notification ?) + * + * This method request syncedItem.instance to confirm its validity directly from the said source. + * It also creates/updates the entry in `circles_item`. + * + * @param SyncedItem $syncedItem + * + * @throws FederatedItemException + * @throws FederatedSyncConflictException + * @throws InvalidItemException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws SyncedItemNotFoundException + * @throws UnknownRemoteException + * @throws InvalidIdException + * @throws FederatedSyncManagerNotFoundException + */ + public function updateSyncedItem(SyncedItem $syncedItem): void { + $this->debugService->info( + 'updating SyncedItem {syncedItem.singleId} from {syncedItem.instance}', '', + ['syncedItem' => $syncedItem] + ); + + try { + $remoteItem = $this->confirmRemoteSyncedItem($syncedItem); + } catch (SyncedItemNotFoundException $e) { + $this->debugService->info('ERROR 404 !?'); + // TODO: delete entry in circles_item and circles_share ? + $this->debugService->exception($e); + throw $e; + } catch (Exception $e) { + $this->debugService->exception($e); + throw $e; + } + + $this->debugService->info( + 'remote SyncedItem {syncedItem.singleId} received with Checksum {remoteItem.checksum}', '', + [ + 'syncedItem' => $syncedItem, + 'remoteItem' => $remoteItem + ] + ); + + try { + $localItem = $this->syncedItemRequest->getSyncedItemFromSingleId($remoteItem->getSingleId()); + if ($localItem->getChecksum() === $remoteItem->getChecksum()) { + $this->debugService->info( + 'local Checksum {syncedItem.checksum} for SyncedItem {syncedItem.singleId} is identical; no update needed', + '', + [ + 'syncedItem' => $syncedItem, + 'remoteItem' => $remoteItem + ] + ); + + return; + } + } catch (SyncedItemNotFoundException $e) { + } + + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + $this->debugService->info( + 'no conflict found yet, calling {`syncItem()} on {syncManager.class} to create/update local entry', + '', + ['syncManager' => ['class' => get_class($syncManager)]] + ); + + $syncManager->syncItem($syncedItem->getItemId(), $remoteItem->getSerialized()); + $this->debugService->info( + 'storing SyncedItem {syncedItem.singleId} into database as no local entry found', + '', + [ + 'syncedItem' => $syncedItem, + 'remoteItem' => $remoteItem + ] + ); + + $this->syncedItemRequest->save($remoteItem); + } +} diff --git a/lib/Service/FederatedSyncService.php b/lib/Service/FederatedSyncService.php new file mode 100644 index 000000000..2ae6e10d1 --- /dev/null +++ b/lib/Service/FederatedSyncService.php @@ -0,0 +1,139 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Service; + +use OCA\Circles\Db\RemoteRequest; +use OCA\Circles\Db\SyncedItemRequest; +use OCA\Circles\Db\SyncedShareRequest; +use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; +use OCA\Circles\IFederatedSyncManager; +use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Tools\ActivityPub\NCSignature; +use OCA\Circles\Tools\Model\Request; +use OCA\Circles\Tools\Traits\TStringTools; + +class FederatedSyncService extends NCSignature { + use TStringTools; + + private SyncedItemRequest $syncedItemRequest; + private SyncedShareRequest $syncedShareRequest; + private RemoteRequest $remoteRequest; + private FederatedEventService $federatedEventService; + private RemoteStreamService $remoteStreamService; + private InterfaceService $interfaceService; + + /** @var IFederatedSyncManager[] */ + private array $syncManager = []; + + + /** + * @param SyncedItemRequest $syncedItemRequest + * @param SyncedShareRequest $syncedShareRequest + * @param RemoteRequest $remoteRequest + * @param FederatedEventService $federatedEventService + * @param RemoteStreamService $remoteStreamService + * @param InterfaceService $interfaceService + */ + public function __construct( + SyncedItemRequest $syncedItemRequest, + SyncedShareRequest $syncedShareRequest, + RemoteRequest $remoteRequest, + FederatedEventService $federatedEventService, + RemoteStreamService $remoteStreamService, + InterfaceService $interfaceService + ) { + $this->syncedItemRequest = $syncedItemRequest; + $this->syncedShareRequest = $syncedShareRequest; + $this->remoteRequest = $remoteRequest; + $this->federatedEventService = $federatedEventService; + $this->remoteStreamService = $remoteStreamService; + $this->interfaceService = $interfaceService; + } + + + /** + * @param IFederatedSyncManager $federatedSyncManager + */ + public function addFederatedSyncManager(IFederatedSyncManager $federatedSyncManager): void { + $this->syncManager[] = $federatedSyncManager; + } + + + /** + * @param string $appId + * @param string $itemType + * + * @return IFederatedSyncManager + * @throws FederatedSyncManagerNotFoundException + */ + public function getSyncManager(string $appId, string $itemType): IFederatedSyncManager { + foreach ($this->syncManager as $federatedSyncManager) { + if ($federatedSyncManager->getAppId() === $appId + && $federatedSyncManager->getItemType() === $itemType) { + return $federatedSyncManager; + } + } + + throw new FederatedSyncManagerNotFoundException(); + } + + + /** + * @param SyncedItem $syncedItem + * + * @return IFederatedSyncManager + * @throws FederatedSyncManagerNotFoundException + */ + public function initSyncManager(SyncedItem $syncedItem): IFederatedSyncManager { + return $this->getSyncManager($syncedItem->getAppId(), $syncedItem->getItemType()); + } + + + + // + public function reachInstance(string $instance) { +// $remoteInstance = $this->remoteRequest->getFromInstance($instance); + $syncedItem = new SyncedItem(); + $syncedItem->setSingleId('toto'); + +// $this->interfaceService->setCurrentInterface($remoteInstance->getInterface()); + $data = $this->remoteStreamService->resultRequestRemoteInstance( + $instance, + RemoteInstance::SYNC_ITEM, + Request::TYPE_POST, + $syncedItem + ); + + echo 'reached !? ' . json_encode($data) . "\n"; + } + +} diff --git a/lib/Service/FederatedSyncShareService.php b/lib/Service/FederatedSyncShareService.php new file mode 100644 index 000000000..fe7e55eb8 --- /dev/null +++ b/lib/Service/FederatedSyncShareService.php @@ -0,0 +1,313 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Service; + +use OCA\Circles\Db\MemberRequest; +use OCA\Circles\Db\RemoteRequest; +use OCA\Circles\Db\SyncedItemRequest; +use OCA\Circles\Db\SyncedShareRequest; +use OCA\Circles\Exceptions\FederatedEventException; +use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; +use OCA\Circles\Exceptions\InitiatorNotConfirmedException; +use OCA\Circles\Exceptions\OwnerNotFoundException; +use OCA\Circles\Exceptions\RemoteInstanceException; +use OCA\Circles\Exceptions\RemoteNotFoundException; +use OCA\Circles\Exceptions\RemoteResourceNotFoundException; +use OCA\Circles\Exceptions\RequestBuilderException; +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\Exceptions\SyncedSharedAlreadyExistException; +use OCA\Circles\Exceptions\SyncedShareNotFoundException; +use OCA\Circles\Exceptions\UnknownRemoteException; +use OCA\Circles\FederatedItems\FederatedSync\ShareCreation; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\FederatedUser; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Model\SyncedShare; +use OCA\Circles\Tools\ActivityPub\NCSignature; +use OCA\Circles\Tools\Model\SimpleDataStore; +use OCA\Circles\Tools\Traits\TStringTools; + +class FederatedSyncShareService extends NCSignature { + use TStringTools; + + private MemberRequest $memberRequest; + private SyncedItemRequest $syncedItemRequest; + private SyncedShareRequest $syncedShareRequest; + private RemoteRequest $remoteRequest; + private FederatedSyncService $federatedSyncService; + private FederatedEventService $federatedEventService; + private RemoteStreamService $remoteStreamService; + private InterfaceService $interfaceService; + private DebugService $debugService; + + + /** + * @param SyncedItemRequest $syncedItemRequest + * @param SyncedShareRequest $syncedShareRequest + * @param RemoteRequest $remoteRequest + * @param FederatedSyncService $federatedSyncService + * @param FederatedEventService $federatedEventService + * @param RemoteStreamService $remoteStreamService + * @param InterfaceService $interfaceService + * @param DebugService $debugService + */ + public function __construct( + MemberRequest $memberRequest, + SyncedItemRequest $syncedItemRequest, + SyncedShareRequest $syncedShareRequest, + RemoteRequest $remoteRequest, + FederatedSyncService $federatedSyncService, + FederatedEventService $federatedEventService, + RemoteStreamService $remoteStreamService, + InterfaceService $interfaceService, + DebugService $debugService + ) { + $this->memberRequest = $memberRequest; + $this->syncedItemRequest = $syncedItemRequest; + $this->syncedShareRequest = $syncedShareRequest; + $this->remoteRequest = $remoteRequest; + $this->federatedSyncService = $federatedSyncService; + $this->federatedEventService = $federatedEventService; + $this->remoteStreamService = $remoteStreamService; + $this->interfaceService = $interfaceService; + $this->debugService = $debugService; + } + + /** + * search for existing shares in circles_share based on itemSingleId, circleId. + * + * @param SyncedItem $syncedItem + * @param Circle $circle + * @param array $extraData + * + * @throws SyncedSharedAlreadyExistException + * @throws FederatedSyncManagerNotFoundException + */ + public function createShare(SyncedItem $syncedItem, Circle $circle, array $extraData = []) { + if (!$this->isShareCreatable($syncedItem, $circle, $extraData)) { + $this->debugService->info( + 'share of SyncedItem {!syncedItem.singleId} to {!circle.id} is set as not creatable by {!syncedItem.appId}', + $circle->getSingleId(), + [ + 'syncedItem' => $syncedItem, + 'circle' => $circle, + 'extraData' => $extraData + ] + ); + } + + try { + $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); + } catch (SyncedItemNotFoundException $e) { + $this->debugService->info( + 'storing SyncedItem {syncedItem.singleId} in database', '', + ['syncedItem' => $syncedItem] + ); + + $this->syncedItemRequest->save($syncedItem); + } + + $this->syncShareCreation($syncedItem, $circle, $extraData); + $this->broadcastShareCreation($syncedItem, $circle, $extraData); + + $this->debugService->info( + 'SyncedShare created and FederatedSync is on its way; {~end of main process}' + ); + } + + + /** + * @param SyncedItem $syncedItem + * @param Circle $circle + * @param array $extraData + * + * @throws FederatedSyncManagerNotFoundException + */ + public function syncShareCreation(SyncedItem $syncedItem, Circle $circle, array $extraData = []): void { + $syncedShare = new SyncedShare(); + $syncedShare->setSingleId($syncedItem->getSingleId()) + ->setCircleId($circle->getSingleId()); + + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + + $federatedUser = new FederatedUser(); + $federatedUser->importFromIFederatedUser($circle->getInitiator()); + + $this->debugService->info( + 'calling {`onShareCreation()} on {syncManager}', + $syncedShare->getCircleId(), + [ + 'syncManager' => get_class($syncManager), + 'syncedItem' => $syncedItem, + 'syncedShare' => $syncedShare, + 'extraData' => $extraData, + 'initiator' => $circle->getInitiator(), + 'federatedUser' => $federatedUser + ] + ); + + $syncManager->onShareCreation( + $syncedItem->getItemId(), + $syncedShare->getCircleId(), + $extraData, + $federatedUser + ); + + $this->syncedShareRequest->save($syncedShare); + $this->debugService->info( + 'storing SyncedShare of {syncedShare.singleId} to {syncedShare.circleId} in database', + $circle->getSingleId(), + [ + 'syncedItem' => $syncedItem, + 'circle' => $circle, + 'syncedShare' => $syncedShare + ] + ); + } + + + /** + * @param Circle $circle + * @param SyncedItem $syncedItem + * + * @throws FederatedEventException + * @throws FederatedItemException + * @throws InitiatorNotConfirmedException + * @throws OwnerNotFoundException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException + */ + private function broadcastShareCreation( + SyncedItem $syncedItem, + Circle $circle, + array $extraData = [] + ): void { + $event = new FederatedEvent(ShareCreation::class); + $event->setCircle($circle) + ->setSyncedItem($syncedItem) + ->setParams(new SimpleDataStore(['extraData' => $extraData])); + + $this->debugService->info( + 'generating {`IFederatedEvent} using {event.class}', + $circle->getSingleId(), + [ + 'event' => $event, + 'syncedItem' => $syncedItem, + 'circle' => $circle + ] + ); + + $this->federatedEventService->newEvent($event); + } + + + /** + * verify that: + * + * - SyncedShare is not already known + * - app agree on creating this share + * + * @param SyncedItem $syncedItem + * @param Circle $circle + * @param array $extraData + * + * @return bool + * @throws FederatedSyncManagerNotFoundException + * @throws SyncedSharedAlreadyExistException + */ + private function isShareCreatable(SyncedItem $syncedItem, Circle $circle, array $extraData = []): bool { + try { + $this->syncedShareRequest->getShare($syncedItem->getSingleId(), $circle->getsingleId()); + throw new SyncedSharedAlreadyExistException('share already exists'); + } catch (SyncedShareNotFoundException $e) { + } + + + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + $this->debugService->info( + 'sharing of SyncedItem {syncedItem.singleId} looks doable, calling {`isShareCreatable()} on {syncManager.class} for confirmation', + $circle->getSingleId(), + [ + 'syncedItem' => $syncedItem, + 'syncManager' => ['class' => get_class($syncManager)] + ] + ); + + return $syncManager->isShareCreatable( + $syncedItem->getItemId(), + $circle->getSingleId(), + $extraData, + $circle->getInitiator()->getInheritedBy() + ); + } + + + /** + * @param string $syncedId + * @param string $instance + * + * @throws RequestBuilderException + * @throws SyncedShareNotFoundException + */ + public function confirmRemoteInstanceAccess(string $syncedId, string $instance): void { + $circleIds = array_values( + array_map( + function (SyncedShare $share): string { + return $share->getCircleId(); + }, + $this->syncedShareRequest->getShares($syncedId) + ) + ); + + // might look nasty to use memberRequest instead membershipRequest, but it is easier this way + // as we are only interested in direct membership to the current circle. + // federated circles only works as root, so sub-circles cannot spread on multiple instances. + $links = $this->memberRequest->getLinksWithInstance($instance, $circleIds); + $this->debugService->info( + 'SyncedItem {singleId} is shared to ' . count($circleIds) . ' circles', '', + [ + 'syncedId' => $syncedId, + 'circleIds' => $circleIds, + 'links' => $links + ] + ); + + if (empty($links)) { + throw new SyncedShareNotFoundException('instance have no access to this item'); + } + } + +} diff --git a/lib/Service/RemoteDownstreamService.php b/lib/Service/RemoteDownstreamService.php index 3385292b9..03f6385ad 100644 --- a/lib/Service/RemoteDownstreamService.php +++ b/lib/Service/RemoteDownstreamService.php @@ -31,11 +31,6 @@ namespace OCA\Circles\Service; -use OCA\Circles\Tools\Exceptions\InvalidItemException; -use OCA\Circles\Tools\Exceptions\RequestNetworkException; -use OCA\Circles\Tools\Exceptions\SignatoryException; -use OCA\Circles\Tools\Traits\TAsync; -use OCA\Circles\Tools\Traits\TNCLogger; use Exception; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\MemberRequest; @@ -54,6 +49,11 @@ use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Exceptions\RequestNetworkException; +use OCA\Circles\Tools\Exceptions\SignatoryException; +use OCA\Circles\Tools\Traits\TAsync; +use OCA\Circles\Tools\Traits\TNCLogger; /** * Class RemoteDownstreamService @@ -80,6 +80,7 @@ class RemoteDownstreamService { /** @var ConfigService */ private $configService; + private DebugService $debugService; /** * RemoteDownstreamService constructor. @@ -87,14 +88,17 @@ class RemoteDownstreamService { * @param CircleRequest $circleRequest * @param MemberRequest $memberRequest * @param FederatedEventService $federatedEventService + * @param RemoteService $remoteService * @param ConfigService $configService + * @param DebugService $debugService */ public function __construct( CircleRequest $circleRequest, MemberRequest $memberRequest, FederatedEventService $federatedEventService, RemoteService $remoteService, - ConfigService $configService + ConfigService $configService, + DebugService $debugService ) { $this->setup('app', 'circles'); @@ -103,6 +107,7 @@ public function __construct( $this->federatedEventService = $federatedEventService; $this->remoteService = $remoteService; $this->configService = $configService; + $this->debugService = $debugService; } @@ -157,6 +162,12 @@ public function requestedEvent(FederatedEvent $event): void { $this->federatedEventService->confirmInitiator($event, false); $this->confirmContent($event, true); + $this->debugService->info( + '{`IFederatedEvent} looks good; calling {`verify()} on {event.class}', '', + ['event' => $event] + ); + + $item->verify($event); $event->resetResult(); @@ -165,6 +176,11 @@ public function requestedEvent(FederatedEvent $event): void { } if (!$event->isAsync()) { + $this->debugService->info( + 'FederatedEvent is not set as {Async}; calling {`manage()} on {event.class} on current process', + '', + ['event' => $event] + ); $item->manage($event); } diff --git a/lib/Service/RemoteStreamService.php b/lib/Service/RemoteStreamService.php index 8ff9232dd..07ffb262f 100644 --- a/lib/Service/RemoteStreamService.php +++ b/lib/Service/RemoteStreamService.php @@ -177,6 +177,10 @@ public function getAppSignatory(bool $generate = true, string $confirmKey = ''): ) ); + $app->setSyncItem($this->interfaceService->getCloudPath('circles.Remote.syncItem')); + $app->setSyncShare($this->interfaceService->getCloudPath('circles.Remote.syncShare')); + $app->setDebug($this->interfaceService->getCloudPath('circles.Remote.debugDaemon')); + if ($this->interfaceService->isCurrentInterfaceInternal()) { $app->setAliases(array_values(array_filter($this->interfaceService->getInterfaces(false)))); } diff --git a/lib/Service/SignedControllerService.php b/lib/Service/SignedControllerService.php new file mode 100644 index 000000000..e48a53f66 --- /dev/null +++ b/lib/Service/SignedControllerService.php @@ -0,0 +1,314 @@ + + * @copyright 2017 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +declare(strict_types=1); + + +/** + * Circles - Bring cloud-users closer together. + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Maxence Lange + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Service; + +use Exception; +use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException; +use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\Exceptions\FederatedUserException; +use OCA\Circles\Exceptions\JsonNotRequestedException; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Model\FederatedUser; +use OCA\Circles\Model\Member; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Exceptions\InvalidOriginException; +use OCA\Circles\Tools\Exceptions\ItemNotFoundException; +use OCA\Circles\Tools\Exceptions\MalformedArrayException; +use OCA\Circles\Tools\Exceptions\SignatoryException; +use OCA\Circles\Tools\Exceptions\SignatureException; +use OCA\Circles\Tools\Exceptions\UnknownTypeException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\Model\NCSignedRequest; +use OCA\Circles\Tools\Model\SimpleDataStore; +use OCA\Circles\Tools\Traits\TDeserialize; +use OCA\Circles\Tools\Traits\TNCLocalSignatory; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IUserSession; + +class SignedControllerService { + use TNCLocalSignatory; + use TDeserialize; + + + protected RemoteStreamService $remoteStreamService; + protected InterfaceService $interfaceService; + protected FederatedUserService $federatedUserService; + protected ConfigService $configService; + + + public function __construct( + IUserSession $userSession, + FederatedUserService $federatedUserService, + InterfaceService $interfaceService, + RemoteStreamService $remoteStreamService, + ConfigService $configService + ) { + + $this->remoteStreamService = $remoteStreamService; + $this->interfaceService = $interfaceService; + $this->federatedUserService = $federatedUserService; + $this->configService = $configService; + } + + + /** + * @return FederatedEvent + * @throws InvalidOriginException + * @throws MalformedArrayException + * @throws SignatoryException + * @throws SignatureException + */ + public function extractEventFromRequest(): FederatedEvent { + /** @var NCSignedRequest $signed */ + $event = $this->extractObjectFromRequest(FederatedEvent::class, $signed); + $event->setSender($signed->getOrigin()); + + return $event; + } + + /** + * @param string $class + * @param NCSignedRequest|null $signed + * + * @return FederatedEvent + * @throws InvalidOriginException + * @throws MalformedArrayException + * @throws SignatoryException + * @throws SignatureException + */ + public function extractObjectFromRequest( + string $class, + ?NCSignedRequest &$signed = null + ): IDeserializable { + $signed = $this->remoteStreamService->incomingSignedRequest(); + $this->confirmRemoteInstance($signed); + + $obj = new $class(); + $obj->import(json_decode($signed->getBody(), true)); + + return $obj; + } + + + /** + * @return SimpleDataStore + * @throws FederatedUserException + * @throws InvalidOriginException + * @throws MalformedArrayException + * @throws SignatoryException + * @throws SignatureException + * @throws UnknownTypeException + */ + public function extractDataFromFromRequest(): SimpleDataStore { + $signed = $this->remoteStreamService->incomingSignedRequest(); + $remoteInstance = $this->confirmRemoteInstance($signed); + + // There should be no need to confirm the need or the origin of the initiator as $remoteInstance + // already helps filtering request to the database. + // initiator here is only used to play with the visibility, on top of the visibility provided to + // the remote instance based on its type. + $this->federatedUserService->setRemoteInstance($remoteInstance); + + $data = new SimpleDataStore(); + $store = new SimpleDataStore(json_decode($signed->getBody(), true)); + try { + /** @var FederatedUser $initiator */ + $initiator = $store->gObj('initiator', FederatedUser::class); + $this->federatedUserService->setCurrentUser($initiator); + } catch (InvalidItemException | ItemNotFoundException $e) { + } + + try { + /** @var FederatedUser $initiator */ + $filterMember = $store->gObj('filterMember', Member::class); + $data->aObj('filterMember', $filterMember); + } catch (InvalidItemException | ItemNotFoundException $e) { + } + + try { + /** @var FederatedUser $initiator */ + $filterCircle = $store->gObj('filterCircle', Circle::class); + $data->aObj('filterCircle', $filterCircle); + } catch (InvalidItemException | ItemNotFoundException $e) { + } + + return $data; + } + + + /** + * @param NCSignedRequest $signedRequest + * + * @return RemoteInstance + * @throws SignatoryException + */ + private function confirmRemoteInstance(NCSignedRequest $signedRequest): RemoteInstance { + /** @var RemoteInstance $signatory */ + $signatory = $signedRequest->getSignatory(); + + if (!$signatory instanceof RemoteInstance) { + $this->debug('Signatory is not a known RemoteInstance', ['signedRequest' => $signedRequest]); + throw new SignatoryException('Could not confirm identity'); + } + + if (!$this->configService->isLocalInstance($signedRequest->getOrigin()) + && $signatory->getType() === RemoteInstance::TYPE_UNKNOWN) { + $this->debug('Could not confirm identity', ['signedRequest' => $signedRequest]); + throw new SignatoryException('Could not confirm identity'); + } + + $this->interfaceService->setCurrentInterface($signatory->getInterface()); + + return $signatory; + } + + + /** + * @param Exception $e + * @param int $httpErrorCode + * + * @return DataResponse + */ + public function exceptionResponse( + Exception $e, + int $httpErrorCode = Http::STATUS_BAD_REQUEST + ): DataResponse { + if ($e instanceof FederatedItemException) { + return new DataResponse($this->serialize($e), $e->getStatus()); + } + + return new DataResponse( + [ + 'message' => $e->getMessage(), + 'code' => $e->getCode() + ], + ($e->getCode() > 0) ? $e->getCode() : $httpErrorCode + ); + } + + + /** + * use this one if a method from a Controller is only PublicPage when remote client asking for Json + * + * try { + * $this->publicPageJsonLimited(); + * return new DataResponse(['test' => 42]); + * } catch (JsonNotRequestedException $e) {} + * + * + * @throws NotLoggedInException + * @throws JsonNotRequestedException + */ + private function publicPageJsonLimited(): void { + if (!$this->jsonRequested()) { + if (!$this->userSession->isLoggedIn()) { + throw new NotLoggedInException(); + } + + throw new JsonNotRequestedException(); + } + } + + + /** + * @return bool + */ + private function jsonRequested(): bool { + return ($this->areWithinAcceptHeader( + [ + 'application/json', + 'application/ld+json', + 'application/activity+json' + ] + )); + } + + + /** + * @param array $needles + * + * @return bool + */ + private function areWithinAcceptHeader(array $needles): bool { + $accepts = array_map([$this, 'trimHeader'], explode(',', $this->request->getHeader('Accept'))); + + foreach ($accepts as $accept) { + if (in_array($accept, $needles)) { + return true; + } + } + + return false; + } + + /** + * @param string $header + * + * @return string + */ + private function trimHeader(string $header): string { + $header = trim($header); + $pos = strpos($header, ';'); + if ($pos === false) { + return $header; + } + + return substr($header, 0, $pos); + } +} diff --git a/lib/IFederatedSync.php b/lib/Tools/ISignedModel.php similarity index 72% rename from lib/IFederatedSync.php rename to lib/Tools/ISignedModel.php index 25683e685..67dcdc0a1 100644 --- a/lib/IFederatedSync.php +++ b/lib/Tools/ISignedModel.php @@ -3,6 +3,7 @@ declare(strict_types=1); + /** * Circles - Bring cloud-users closer together. * @@ -10,7 +11,7 @@ * later. See the COPYING file. * * @author Maxence Lange - * @copyright 2021 + * @copyright 2022 * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify @@ -29,26 +30,29 @@ */ -namespace OCA\Circles; - -use OCA\Circles\Tools\Model\SimpleDataStore; +namespace OCA\Circles\Tools; -/** - * Interface IFederatedSync - * - * @package OCA\Circles - */ -interface IFederatedSync { +interface ISignedModel { /** - * @param string $circleId + * @param string $signature * - * @return SimpleDataStore + * @return $this + */ + public function setSignature(string $signature): self; + + /** + * @return string */ - public function export(string $circleId): SimpleDataStore; + public function getSignature(): string; + /** - * @param SimpleDataStore $data + * returns array/data to be signed to identify the model + * + * @return array */ - public function import(SimpleDataStore $data): void; + public function signedData(): array; + } + diff --git a/lib/Tools/Model/ReferencedDataStore.php b/lib/Tools/Model/ReferencedDataStore.php new file mode 100644 index 000000000..0dc2ab7a0 --- /dev/null +++ b/lib/Tools/Model/ReferencedDataStore.php @@ -0,0 +1,473 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Tools\Model; + +use JetBrains\PhpStorm\Pure; +use JsonSerializable; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Exceptions\ItemNotFoundException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; +use OCA\Circles\Tools\Traits\TArrayTools; +use OCA\Circles\Tools\Traits\TDeserialize; +use ReflectionClass; +use ReflectionException; + +class ReferencedDataStore implements IDeserializable, JsonSerializable { + use TArrayTools; + use TDeserialize; + + public const STRING = 'string'; + public const INTEGER = 'integer'; + public const BOOLEAN = 'boolean'; + public const ARRAY = 'array'; + public const OBJECT = 'object'; + + public const KEY_NAME = 'name'; + public const KEY_TYPE = 'type'; + public const KEY_CLASS = 'class'; + + public const _THIS = '__this'; + public const _REFERENCE = '__reference'; + + private array $ref = []; + private array $data = []; + private string $lock = IReferencedObject::class; + + public function __construct(array $data = []) { + $this->data = $data; + } + + + /** + * @param string $key + * @param string $value + * + * @return ReferencedDataStore + */ + public function s(string $key, string $value): self { + $this->data[$key] = $value; + $this->ref($key, self::STRING); + + return $this; + } + + /** + * @param string $key + * + * @return string + * @throws InvalidItemException + */ + public function g(string $key): string { + $this->confirmRef($key, self::STRING); + + return $this->get($key, $this->data); + } + + + /** + * @param string $key + * + * @return ReferencedDataStore + */ + public function u(string $key): self { + if ($this->hasKey($key)) { + unset($this->data[$key]); + } + + return $this; + } + + + /** + * @param string $key + * @param int $value + * + * @return ReferencedDataStore + */ + public function sInt(string $key, int $value): self { + $this->data[$key] = $value; + $this->ref($key, self::INTEGER); + + return $this; + } + + /** + * @param string $key + * + * @return int + * @throws InvalidItemException + */ + public function gInt(string $key): int { + $this->confirmRef($key, self::INTEGER); + + return $this->getInt($key, $this->data); + } + + + /** + * @param string $key + * @param bool $value + * + * @return ReferencedDataStore + */ + public function sBool(string $key, bool $value): self { + $this->data[$key] = $value; + $this->ref($key, self::BOOLEAN); + + return $this; + } + + /** + * @param string $key + * + * @return bool + * @throws InvalidItemException + */ + public function gBool(string $key): bool { + $this->confirmRef($key, self::BOOLEAN); + + return $this->getBool($key, $this->data); + } + + + /** + * @param string $key + * @param array $value + * + * @return ReferencedDataStore + */ + public function sArray(string $key, array $value): self { + $this->data[$key] = $value; + $this->ref($key, self::ARRAY); + + return $this; + } + + /** + * @param string $key + * + * @return array + * @throws InvalidItemException + */ + public function gArray(string $key): array { + $this->confirmRef($key, self::ARRAY); + + return $this->getArray($key, $this->data); + } + + + /** + * @param string $key + * @param JsonSerializable $value + * + * @return ReferencedDataStore + */ + public function sObj(string $key, JsonSerializable $value): self { + $this->data[$key] = $value; + $this->ref($key, self::OBJECT, $value); + + return $this; + } + + + /** + * @param string $key + * @param string $class + * + * @return JsonSerializable[] + */ +// public function gObjs(string $key, string $class = ''): array { +// $list = $this->gArray($key); +// $result = []; +// foreach ($list as $item) { +// $data = new SimpleDataStore([$key => $item]); +// $result[] = $data->gObj($key, $class); +// } +// +// return array_filter($result); +// } + + + /** + * @param string $key + * + * @return null|JsonSerializable + * @throws InvalidItemException + */ + public function gObj(string $key): ?IDeserializable { + $this->confirmRef($key, self::OBJECT); + $class = $this->getRef($key, self::KEY_CLASS); + + $item = $this->data[$key]; + if ($item instanceof IDeserializable) { + return $item; + } + + try { + $reflection = new ReflectionClass($class); + } catch (ReflectionException $e) { + throw new InvalidItemException('reflection issue with ' . $class); + } + + if (!$reflection->implementsInterface(IDeserializable::class)) { + throw new InvalidItemException('object does not implements IDeserializable'); + } + + if ($this->locked() !== '' && !$reflection->implementsInterface($this->locked())) { + throw new InvalidItemException('model is locked'); + } + + return $this->deserialize($item, $class); + } + + + /** + * @param string $key + * + * @return mixed + * @throws ItemNotFoundException + */ +// public function gItem(string $key) { +// if (!array_key_exists($key, $this->data)) { +// throw new ItemNotFoundException(); +// } +// +// return $this->data[$key]; +// } + + + /** + * @param string $k + * @param mixed $obj + * + * @return ReferencedDataStore + * @throws InvalidItemException + */ + public function sMixed(string $k, mixed $obj): self { + if ($obj instanceof JsonSerializable) { + return $this->sObj($k, $obj); + } + if (is_array($obj)) { + return $this->sArray($k, $obj); + } + if (is_integer($obj)) { + return $this->sInt($k, $obj); + } + if (is_string($obj)) { + return $this->s($k, $obj); + } + if (is_bool($obj)) { + return $this->sBool($k, $obj); + } + + throw new InvalidItemException(); + } + + + /** + * @param string $json + * + * @return $this + * @throws InvalidItemException + */ + public function json(string $json): self { + $this->import(json_decode($json, true)); + + return $this; + } + + + public function keys(): array { + return array_keys($this->data); + } + + /** + * @param string $key + * + * @return bool + */ + public function hasKey(string $key): bool { + return (array_key_exists($key, $this->data)); + } + + + /** + * @param array $keys + * + * @return bool + */ + #[Pure] + public function hasKeys(array $keys): bool { + foreach ($keys as $key) { + if (!$this->hasKey($key)) { + return false; + } + } + + return true; + } + + + /** + * @param string $lock + * + * @return $this + */ + public function lock(string $lock): self { + $this->lock = $lock; + + return $this; + } + + /** + * @return $this + */ + public function unlock(): self { + $this->lock = ''; + + return $this; + } + + /** + * @return string + */ + public function locked(): string { + return $this->lock; + } + + + /** + * @return array + */ + public function gAll(): array { + return $this->data; + } + + + /** + * @param string $key + * @param string $type + * @param JsonSerializable|null $object + * + * @return $this + */ + private function ref(string $key, string $type, ?JsonSerializable $object = null): self { + $ref = [self::KEY_TYPE => $type]; + + if ($key !== self::_THIS) { + $ref[self::KEY_NAME] = $key; + } + + if (!is_null($object)) { + $ref[self::KEY_CLASS] = get_class($object); + } + + $this->ref[$key] = $ref; + + return $this; + } + + /** + * @param string $key + * @param string $ref + * + * @return string + */ + private function getRef(string $key, string $ref): string { + return $this->get($key . '.' . $ref, $this->ref); + } + + /** + * @param string $key + * @param string $type + * + * @throws InvalidItemException + */ + private function confirmRef(string $key, string $type): void { + if ($this->getRef($key, self::KEY_TYPE) === $type) { + return; + } + + throw new InvalidItemException(); + } + + public function getType(string $key): string { + return $this->getRef($key, self::KEY_TYPE); + } + + + /** + * @return array + */ + public function getAllReferences(): array { + $ref = $this->ref; + unset($ref[self::_THIS]); + + return $ref; + } + + /** + * @param array $data + * + * @return IDeserializable + * @throws InvalidItemException + */ + public function import(array $data): IDeserializable { + $this->ref = $this->getArray(self::_REFERENCE, $data); + + if ($this->getRef(self::_THIS, self::KEY_TYPE) !== self::OBJECT + || $this->getRef(self::_THIS, self::KEY_CLASS) !== get_class($this)) { + throw new InvalidItemException(); + } + + unset($data[self::_REFERENCE]); + $this->data = $data; + + return $this; + } + + + /** + * @return array + */ + public function jsonSerialize(): array { + $this->ref(self::_THIS, self::OBJECT, $this); + + return array_merge( + [ + '__reference' => $this->ref, + ], + $this->data + ); + } +} diff --git a/lib/Tools/Traits/TNCSignatory.php b/lib/Tools/Traits/TNCSignatory.php index 0d28fedf1..deeed009b 100644 --- a/lib/Tools/Traits/TNCSignatory.php +++ b/lib/Tools/Traits/TNCSignatory.php @@ -35,6 +35,7 @@ use OCA\Circles\Tools\Exceptions\RequestNetworkException; use OCA\Circles\Tools\Exceptions\SignatoryException; use OCA\Circles\Tools\Exceptions\SignatureException; +use OCA\Circles\Tools\ISignedModel; use OCA\Circles\Tools\Model\NCRequest; use OCA\Circles\Tools\Model\NCSignatory; @@ -189,6 +190,19 @@ public function signString(string $clear, NCSignatory $signatory): string { } + /** + * @param ISignedModel $model + * @param NCSignatory $signatory + * + * @throws SignatoryException + */ + public function signModel(ISignedModel $model, NCSignatory $signatory): void { + $string = json_encode($model->signedData()); + $signature = $this->signString($string, $signatory); + $model->setSignature($signature); + } + + /** * @param string $clear * @param string $signed @@ -204,4 +218,20 @@ public function verifyString( throw new SignatureException('signature issue'); } } + + /** + * @param ISignedModel $model + * @param string $publicKey + * @param string $algo + * + * @throws SignatureException + */ + public function verifyModel( + ISignedModel $model, + string $publicKey, + string $algo = NCSignatory::SHA256 + ): void { + $string = json_encode($model->signedData()); + $this->verifyString($string, $model->getSignature(), $publicKey, $algo); + } } From 6f46d3fa4fda1a3d01d922931f8fee8b81988b6b Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Wed, 25 May 2022 12:14:04 -0100 Subject: [PATCH 2/5] updateItem Signed-off-by: Maxence Lange --- appinfo/routes.php | 1 + lib/CircleSharesManager.php | 84 +++- lib/Command/CirclesDebug.php | 10 +- lib/Controller/SyncController.php | 60 +++ lib/Db/SyncedItemRequest.php | 15 +- .../FederatedSync/ItemUpdate.php | 163 ++++++++ .../FederatedSync/ShareCreation.php | 98 +---- lib/IFederatedPartialSyncManager.php | 39 ++ lib/IFederatedSyncManager.php | 39 +- lib/Model/Debug.php | 2 - lib/Model/SyncedItem.php | 2 +- lib/Model/SyncedWrapper.php | 206 ++++++++++ lib/Service/FederatedSyncItemService.php | 374 +++++++++++++++++- lib/Service/FederatedSyncService.php | 19 +- lib/Service/FederatedSyncShareService.php | 11 - lib/Service/ShareWrapperService.php | 2 +- lib/Service/SignedControllerService.php | 6 +- lib/Tools/Model/ReferencedDataStore.php | 2 - lib/Tools/Traits/TDeserialize.php | 22 +- 19 files changed, 982 insertions(+), 173 deletions(-) create mode 100644 lib/FederatedItems/FederatedSync/ItemUpdate.php create mode 100644 lib/IFederatedPartialSyncManager.php create mode 100644 lib/Model/SyncedWrapper.php diff --git a/appinfo/routes.php b/appinfo/routes.php index a8ac259c5..2ce2639a0 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -115,6 +115,7 @@ ['name' => 'Remote#memberships', 'url' => '/memberships/{circleId}/', 'verb' => 'GET'], ['name' => 'Sync#getSyncedItem', 'url' => '/sync/item', 'verb' => 'GET'], + ['name' => 'Sync#updateSyncedItem', 'url' => '/sync/item', 'verb' => 'PUT'], // ['name' => 'Remote#syncItem', 'url' => '/sync/item/{singleId}', 'verb' => 'GET'], ['name' => 'Sync#syncShare', 'url' => '/sync/share', 'verb' => 'POST'], ['name' => 'Debug#debugDaemon', 'url' => '/debug', 'verb' => 'POST'] diff --git a/lib/CircleSharesManager.php b/lib/CircleSharesManager.php index 4a09d28cb..f5729e53f 100644 --- a/lib/CircleSharesManager.php +++ b/lib/CircleSharesManager.php @@ -40,6 +40,7 @@ use OCA\Circles\Service\FederatedSyncItemService; use OCA\Circles\Service\FederatedSyncService; use OCA\Circles\Service\FederatedSyncShareService; +use OCA\Circles\Service\FederatedUserService; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; @@ -52,6 +53,7 @@ class CircleSharesManager implements ICircleSharesManager { private CircleService $circleService; + private FederatedUserService $federatedUserService; private FederatedSyncService $federatedSyncService; private FederatedSyncItemService $federatedSyncItemService; private FederatedSyncShareService $federatedSyncShareService; @@ -64,12 +66,16 @@ class CircleSharesManager implements ICircleSharesManager { /** * @param CircleService $circleService + * @param FederatedUserService $federatedUserService + * @param FederatedSyncService $federatedSyncService * @param FederatedSyncItemService $federatedSyncItemService * @param FederatedSyncShareService $federatedSyncShareService * @param ConfigService $configService + * @param DebugService $debugService */ public function __construct( CircleService $circleService, + FederatedUserService $federatedUserService, FederatedSyncService $federatedSyncService, FederatedSyncItemService $federatedSyncItemService, FederatedSyncShareService $federatedSyncShareService, @@ -77,6 +83,7 @@ public function __construct( DebugService $debugService ) { $this->circleService = $circleService; + $this->federatedUserService = $federatedUserService; $this->federatedSyncService = $federatedSyncService; $this->federatedSyncItemService = $federatedSyncItemService; $this->federatedSyncShareService = $federatedSyncShareService; @@ -125,12 +132,14 @@ public function createShare( array $extraData = [] ): void { $this->debugService->setDebugType('federated_sync'); - $this->debugService->info('{~New request to create a SyncedShare} based on {appId}.{itemType}.{itemId}', $circleId, [ - 'appId' => $this->originAppId, - 'itemType' => $this->originItemType, - 'itemId' => $itemId, - 'extraData' => $extraData - ]); + $this->debugService->info( + '{~New request to create a SyncedShare} based on {appId}.{itemType}.{itemId}', $circleId, [ + 'appId' => $this->originAppId, + 'itemType' => $this->originItemType, + 'itemId' => $itemId, + 'extraData' => $extraData + ] + ); try { $this->mustHaveOrigin(); @@ -143,10 +152,11 @@ public function createShare( $circle = $this->circleService->getCircle($circleId, $probe); // get valid SyncedItem based on appId, itemType, itemId - $syncedItem = $this->federatedSyncItemService->getSyncedItem( + $syncedItem = $this->federatedSyncItemService->initSyncedItem( $this->originAppId, $this->originItemType, - $itemId + $itemId, + true ); $this->debugService->info( @@ -170,7 +180,6 @@ public function createShare( $this->debugService->exception($e, $circleId); throw $e; } -// this->$this->federatedItemService->getSharedItem } /** @@ -185,7 +194,6 @@ public function updateShare( string $circleId, array $extraData = [] ): void { - $this->mustHaveOrigin(); } /** @@ -200,15 +208,67 @@ public function deleteShare(string $itemId, string $circleId): void { /** * @param string $itemId - * @param array $serializedData + * @param array $extraData + * + * @throws CircleSharesManagerException */ public function updateItem( string $itemId, - array $serializedData + array $extraData = [] ): void { $this->mustHaveOrigin(); + + $this->debugService->setDebugType('federated_sync'); + $this->debugService->info( + '{~New request to update a SyncedItem} based on {appId}.{itemType}.{itemId}', + '', + [ + 'appId' => $this->originAppId, + 'itemType' => $this->originItemType, + 'itemId' => $itemId, + 'extraData' => $extraData + ] + ); + + try { +// $this->mustHaveOrigin(); + +// // TODO: verify rules that apply when sharing to a circle +// $probe = new CircleProbe(); +// $probe->includeSystemCircles() +// ->mustBeMember(); +// +// $circle = $this->circleService->getCircle($circleId, $probe); +// + // get valid SyncedItem based on appId, itemType, itemId + $syncedItem = $this->federatedSyncItemService->initSyncedItem( + $this->originAppId, + $this->originItemType, + $itemId + ); + + $this->debugService->info( + 'initiating the process of updating {syncedItem.singleId}', + '', [ + 'itemId' => $itemId, + 'syncedItem' => $syncedItem, + 'extraData' => $extraData, + 'isLocal' => $syncedItem->isLocal() + ] + ); + + $this->federatedSyncItemService->requestSyncedItemUpdate( + $this->federatedUserService->getCurrentEntity(), + $syncedItem, + $extraData + ); + } catch (Exception $e) { + $this->debugService->exception($e); + throw $e; + } } + /** * @param string $itemId * diff --git a/lib/Command/CirclesDebug.php b/lib/Command/CirclesDebug.php index 355d21cca..5127d82a1 100644 --- a/lib/Command/CirclesDebug.php +++ b/lib/Command/CirclesDebug.php @@ -32,7 +32,6 @@ namespace OCA\Circles\Command; use Exception; -use JetBrains\PhpStorm\Pure; use OC\Core\Command\Base; use OCA\Circles\Model\Debug; use OCA\Circles\Service\ConfigService; @@ -63,6 +62,7 @@ class CirclesDebug extends Base { private BottomRightPanel $bottomRightPanel; private ProgressBar $display; + private string $localDisplayName; /** @var Panel[] $panels */ private array $panels = []; /** @var Debug[] $debugs */ @@ -72,6 +72,7 @@ class CirclesDebug extends Base { /** * @param DebugService $debugService + * @param ConfigService $configService */ public function __construct(DebugService $debugService, ConfigService $configService) { parent::__construct(); @@ -88,6 +89,7 @@ protected function configure() { ->addOption('history', '', InputOption::VALUE_REQUIRED, 'last history', '50') ->addOption('size', '', InputOption::VALUE_REQUIRED, 'height', '0') ->addOption('ping', '', InputOption::VALUE_NONE, 'ping debug daemon') + ->addOption('local', '', InputOption::VALUE_REQUIRED, 'set displayed address', 'local') ->addOption('instance', '', InputOption::VALUE_REQUIRED, 'filter instance', ''); } @@ -105,6 +107,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int return 0; } + $this->localDisplayName = $input->getOption('local'); + $this->init(); $this->initTerminal((int)$input->getOption('size')); $this->initPanel($output); @@ -273,7 +277,7 @@ private function refreshHistory(): void { $debug = $item->getDebug(); $instance = ($this->configService->isLocalInstance($item->getInstance())) ? - 'local' : $item->getInstance(); + $this->localDisplayName : $item->getInstance(); $instanceColor = $this->configService->getAppValue('debug_instance.' . $instance); if ($instanceColor === '') { @@ -428,7 +432,6 @@ private function refresh(): void { /** * @return bool */ - #[Pure] private function isRefreshNeeded(): bool { if ($this->refresh) { return true; @@ -454,7 +457,6 @@ private function cleanRefresh(): void { /** * @return Debug */ - #[Pure] private function getSelectedEntry(): Debug { return $this->debugs[$this->topPanel->getCurrentPage() + $this->topPanel->getCurrentLine()]; } diff --git a/lib/Controller/SyncController.php b/lib/Controller/SyncController.php index e2a52e043..37b6f1a55 100644 --- a/lib/Controller/SyncController.php +++ b/lib/Controller/SyncController.php @@ -32,7 +32,9 @@ namespace OCA\Circles\Controller; use Exception; +use OCA\Circles\Exceptions\FederatedItemBadRequestException; use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Model\SyncedWrapper; use OCA\Circles\Service\DebugService; use OCA\Circles\Service\FederatedSyncItemService; use OCA\Circles\Service\FederatedSyncShareService; @@ -116,4 +118,62 @@ public function getSyncedItem(): DataResponse { } } + + /** + * @PublicPage + * @NoCSRFRequired + * + * @return DataResponse + */ + public function updateSyncedItem(): DataResponse { + try { + /** @var SyncedWrapper $wrapper */ + $wrapper = $this->signedControllerService->extractObjectFromRequest( + SyncedWrapper::class, + $signed + ); + + $this->debugService->info( + '{instance} is requesting an update on SyncedItem {syncedItem.singleId}', '', + [ + 'instance' => $signed->getOrigin(), + 'syncedWrapper' => $wrapper + ] + ); + + if (!$wrapper->hasItem() || !$wrapper->hasFederatedUser()) { + throw new FederatedItemBadRequestException(); + } + + $item = $wrapper->getItem(); + $local = $this->federatedSyncItemService->getLocalSyncedItem($item->getSingleId()); + + // confirm that remote is in a circle with a share on the item + $this->federatedSyncShareService->confirmRemoteInstanceAccess( + $local->getSingleId(), + $signed->getOrigin() + ); + + $this->debugService->info( + 'SyncedItem exists, is local, and {instance} have access to the SyncedItem.', '', + [ + 'instance' => $signed->getOrigin(), + 'local' => $local, + ] + ); + + $updated = $this->federatedSyncItemService->requestSyncedItemUpdate( + $wrapper->getFederatedUser(), + $local, + $wrapper->getExtraData() + ); + + return new DataResponse($updated); + } catch (Exception $e) { + $this->e($e); + + return $this->signedControllerService->exceptionResponse($e, Http::STATUS_UNAUTHORIZED); + } + } + } diff --git a/lib/Db/SyncedItemRequest.php b/lib/Db/SyncedItemRequest.php index f3782e3ce..1cff67e3c 100644 --- a/lib/Db/SyncedItemRequest.php +++ b/lib/Db/SyncedItemRequest.php @@ -34,7 +34,6 @@ use OCA\Circles\Exceptions\InvalidIdException; use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\Model\SyncedItem; -use OCA\Circles\Tools\Exceptions\InvalidItemException; /** * Class ShareRequest @@ -65,6 +64,19 @@ public function save(SyncedItem $item): void { } + /** + * @param string $singleId + * @param string $checksum + */ + public function updateChecksum(string $singleId, string $checksum): void { + $qb = $this->getSyncedItemUpdateSql(); + $qb->set('checksum', $qb->createNamedParameter($checksum)); + $qb->limitToSingleId($singleId); + + $qb->executeStatement(); + } + + /** * @param string $singleId * @@ -97,4 +109,5 @@ public function getSyncedItem(string $appId, string $itemType, string $itemId): return $this->getItemFromRequest($qb); } + } diff --git a/lib/FederatedItems/FederatedSync/ItemUpdate.php b/lib/FederatedItems/FederatedSync/ItemUpdate.php new file mode 100644 index 000000000..faa1cb9f4 --- /dev/null +++ b/lib/FederatedItems/FederatedSync/ItemUpdate.php @@ -0,0 +1,163 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\FederatedItems\FederatedSync; + +use OCA\Circles\Db\SyncedItemRequest; +use OCA\Circles\Exceptions\FederatedSyncConflictException; +use OCA\Circles\Exceptions\RequestBuilderException; +use OCA\Circles\IFederatedItem; +use OCA\Circles\IFederatedItemAsyncProcess; +use OCA\Circles\IFederatedItemHighSeverity; +use OCA\Circles\IFederatedItemInitiatorCheckNotRequired; +use OCA\Circles\IFederatedItemLimitedToInstanceWithMember; +use OCA\Circles\IFederatedItemSyncedItem; +use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Service\ConfigService; +use OCA\Circles\Service\DebugService; +use OCA\Circles\Service\FederatedSyncItemService; +use OCA\Circles\Service\FederatedSyncShareService; +use OCA\Circles\Tools\Traits\TDeserialize; + + +class ItemUpdate implements + IFederatedItem, + IFederatedItemLimitedToInstanceWithMember, + IFederatedItemHighSeverity, // needed !? + IFederatedItemAsyncProcess, + IFederatedItemInitiatorCheckNotRequired, + IFederatedItemSyncedItem { + use TDeserialize; + + private SyncedItemRequest $syncedItemRequest; + private FederatedSyncItemService $federatedSyncItemService; + private FederatedSyncShareService $federatedSyncShareService; + private ConfigService $configService; + private DebugService $debugService; + + + /** + * @param SyncedItemRequest $syncedItemRequest + * @param FederatedSyncItemService $federatedSyncItemService + * @param FederatedSyncShareService $federatedSyncShareService + * @param ConfigService $configService + * @param DebugService $debugService + */ + public function __construct( + SyncedItemRequest $syncedItemRequest, + FederatedSyncItemService $federatedSyncItemService, + FederatedSyncShareService $federatedSyncShareService, + ConfigService $configService, + DebugService $debugService + ) { + $this->syncedItemRequest = $syncedItemRequest; + $this->federatedSyncItemService = $federatedSyncItemService; + $this->federatedSyncShareService = $federatedSyncShareService; + $this->configService = $configService; + $this->debugService = $debugService; + } + + + /** + * @param FederatedEvent $event + * + * @throws FederatedSyncConflictException + */ + public function verify(FederatedEvent $event): void { + $syncedItem = $event->getSyncedItem(); + $syncedItem->setInstance($event->getOrigin()); + + $this->federatedSyncItemService->compareWithKnownItem($syncedItem, true); + } + + + /** + * @param FederatedEvent $event + * + * @throws RequestBuilderException + */ + public function manage(FederatedEvent $event): void { + if ($this->configService->isLocalInstance($event->getOrigin())) { + $this->debugService->info( + '{`FederatedEvent} has its origin set as current instance. leaving.', '', + ['event' => $event] + ); + + return; + } + + $syncedItem = $event->getSyncedItem(); + + $this->federatedSyncItemService->compareWithKnownItem($syncedItem, true); + +// $extraData = $event->getParams()->gArray('extraData'); + $this->federatedSyncItemService->updateSyncedItem($syncedItem); + + // if ($this->configService->isLocalInstance($event->getOrigin())) { +// $this->debugService->info( +// '{`FederatedEvent} has its origin set as current instance. leaving.', '', +// ['event' => $event] +// ); +// +// return; +// } +// +// $circle = $event->getCircle(); +// $syncedItem = $event->getSyncedItem(); +// +// try { +// $this->compareWithKnownItemId($syncedItem); +// $this->compareWithKnownSingleId($syncedItem); +// } catch (FederatedSyncConflictException $e) { +// $this->debugService->exception( +// $e, '', +// ['note' => 'WIP: this exception should start the process of fixing conflict'] +// ); +// +// return; // TODO: manage FederatedSyncConflictException - can be done 'live' at this point +// } catch (SyncedItemNotFoundException $e) { +// } +// +// $extraData = $event->getParams()->gArray('extraData'); +// +// $this->federatedSyncItemService->updateSyncedItem($syncedItem); +// $this->federatedSyncShareService->syncShareCreation($syncedItem, $circle, $extraData); + } + + + /** + * @param FederatedEvent $event + * @param array $results + */ + public function result(FederatedEvent $event, array $results): void { + } + +} diff --git a/lib/FederatedItems/FederatedSync/ShareCreation.php b/lib/FederatedItems/FederatedSync/ShareCreation.php index 2b7adead7..6f2ab4fdd 100644 --- a/lib/FederatedItems/FederatedSync/ShareCreation.php +++ b/lib/FederatedItems/FederatedSync/ShareCreation.php @@ -34,14 +34,12 @@ use OCA\Circles\Db\SyncedItemRequest; use OCA\Circles\Exceptions\FederatedSyncConflictException; use OCA\Circles\Exceptions\RequestBuilderException; -use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\IFederatedItem; use OCA\Circles\IFederatedItemAsyncProcess; use OCA\Circles\IFederatedItemHighSeverity; use OCA\Circles\IFederatedItemLimitedToInstanceWithMember; use OCA\Circles\IFederatedItemSyncedItem; use OCA\Circles\Model\Federated\FederatedEvent; -use OCA\Circles\Model\SyncedItem; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\DebugService; use OCA\Circles\Service\FederatedSyncItemService; @@ -92,36 +90,10 @@ public function __construct( * @throws FederatedSyncConflictException */ public function verify(FederatedEvent $event): void { - $circle = $event->getCircle(); $syncedItem = $event->getSyncedItem(); -// $initiator = $circle->getInitiator(); $syncedItem->setInstance($event->getOrigin()); - - try { - $this->compareWithKnownItemId($syncedItem); - $this->compareWithKnownSingleId($syncedItem); - } catch (FederatedSyncConflictException $e) { - $this->debugService->exception( - $e, '', - [ - 'note' => 'WIP: exception is thrown and catch to async process; while returning error', - 'note2' => 'async process will try to fix the conflict' - ] - ); - // TODO: manage FederatedSyncConflictException - should not be run 'live' at this point - // The solution might be to Async the current process with an error while fixing the issue - // on the child process. remote instance will tell the initiator that there is an issue and - // he should try again (estimating the process to fix conflict might takes few seconds. - // To do so, catching the exception earlier instead of here. - throw $e; - } catch (SyncedItemNotFoundException $e) { - $this->debugService->info( - 'no known syncedItem {syncedItem.singleId} were found in database, assuming this is good', - '', - ['syncedItem' => $syncedItem] - ); - } + $this->federatedSyncItemService->compareWithKnownItem($syncedItem, true); } @@ -143,18 +115,7 @@ public function manage(FederatedEvent $event): void { $circle = $event->getCircle(); $syncedItem = $event->getSyncedItem(); - try { - $this->compareWithKnownItemId($syncedItem); - $this->compareWithKnownSingleId($syncedItem); - } catch (FederatedSyncConflictException $e) { - $this->debugService->exception( - $e, '', - ['note' => 'WIP: this exception should start the process of fixing conflict'] - ); - - return; // TODO: manage FederatedSyncConflictException - can be done 'live' at this point - } catch (SyncedItemNotFoundException $e) { - } + $this->federatedSyncItemService->compareWithKnownItem($syncedItem, true); $extraData = $event->getParams()->gArray('extraData'); @@ -170,59 +131,4 @@ public function manage(FederatedEvent $event): void { public function result(FederatedEvent $event, array $results): void { } - - /** - * @throws FederatedSyncConflictException - * @throws SyncedItemNotFoundException - */ - private function compareWithKnownSingleId(SyncedItem $syncedItem): void { - $knownItem = $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); - $this->debugService->info( - 'Comparing with the SyncedItem {syncedItem.singleId} from database: {knownItem.appId}.{knownItem.itemType}.{knownItem.itemId}', - '', - [ - 'syncedItem' => $syncedItem, - 'knownItem' => $knownItem - ] - ); - - if ($knownItem->getAppId() !== $syncedItem->getAppId() - || $knownItem->getItemType() !== $syncedItem->getItemType() - || $knownItem->getInstance() !== $syncedItem->getInstance() - || $knownItem->isDeleted()) { - throw new FederatedSyncConflictException('conflict/dsync on SyncedItem'); - } - } - - - /** - * @param SyncedItem $syncedItem - * - * @throws FederatedSyncConflictException - */ - private function compareWithKnownItemId(SyncedItem $syncedItem): void { - try { - $knownItem = $this->syncedItemRequest->getSyncedItem( - $syncedItem->getAppId(), - $syncedItem->getItemType(), - $syncedItem->getItemId() - ); - } catch (SyncedItemNotFoundException $e) { - return; - } - - $this->debugService->info( - 'Comparing with the SyncedItem {syncedItem.appId}.{syncedItem.itemType}.{syncedItem.itemId} from database: {knownItem.singleId}', - '', - [ - 'syncedItem' => $syncedItem, - 'knownItem' => $knownItem - ] - ); - - if ($knownItem->getSingleId() !== $syncedItem->getSingleId()) { - throw new FederatedSyncConflictException('conflict/dsync on SyncedItem'); - } - } - } diff --git a/lib/IFederatedPartialSyncManager.php b/lib/IFederatedPartialSyncManager.php new file mode 100644 index 000000000..5deabf7a6 --- /dev/null +++ b/lib/IFederatedPartialSyncManager.php @@ -0,0 +1,39 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles; + + +// WIP, do not implement this yet. +interface IFederatedPartialSyncManager { + +} + diff --git a/lib/IFederatedSyncManager.php b/lib/IFederatedSyncManager.php index c10ec0998..cd268771c 100644 --- a/lib/IFederatedSyncManager.php +++ b/lib/IFederatedSyncManager.php @@ -31,9 +31,9 @@ namespace OCA\Circles; +use JsonSerializable; use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\Model\FederatedUser; -use OCA\Circles\Model\Membership; /** * Interface IFederatedSyncManager @@ -149,7 +149,7 @@ public function isShareCreatable( string $itemId, string $circleId, array $extraData, - FederatedUser $federatedUser + IFederatedUser $federatedUser ): bool; @@ -177,7 +177,7 @@ public function onShareCreation( string $itemId, string $circleId, array $extraData, - FederatedUser $federatedUser + IFederatedUser $federatedUser ): void; @@ -188,7 +188,7 @@ public function onShareCreation( * @param string $itemId * @param string $circleId * @param array $extraData - * @param Membership $membership + * @param IFederatedUser $federatedUser * * @return bool */ @@ -196,7 +196,7 @@ public function isShareModifiable( string $itemId, string $circleId, array $extraData, - Membership $membership + IFederatedUser $federatedUser ): bool; @@ -218,13 +218,13 @@ public function isShareModifiable( * @param string $itemId * @param string $circleId * @param array $extraData - * @param Membership $membership + * @param IFederatedUser $federatedUser */ public function onShareModification( string $itemId, string $circleId, array $extraData, - Membership $membership + IFederatedUser $federatedUser ): void; @@ -234,14 +234,14 @@ public function onShareModification( * * @param string $itemId * @param string $circleId - * @param Membership $membership + * @param IFederatedUser $federatedUser * * @return bool */ public function isShareDeletable( string $itemId, string $circleId, - Membership $membership + IFederatedUser $federatedUser ): bool; @@ -259,35 +259,38 @@ public function isShareDeletable( * * @param string $itemId * @param string $circleId - * @param Membership $membership + * @param IFederatedUser $federatedUser */ public function onShareDeletion( string $itemId, string $circleId, - Membership $membership + IFederatedUser $federatedUser ): void; /** - * Your app returns if the item can be updated by $federatedUser. + * Confirm that partial update is doable, throw Exception if not. + * Must returns the serialized data of the future version of the Item. + * + * Your app should not update anything in database at this point. + * + * The serialized data will be used on the next call of syncItem() and store during this next step. * * Membership of $federatedUser can go through multiple paths as the same item can be shared to different * circles $federatedUser is a member. Meaning multiple permissions needs to be checked. * - * $serializedData can be modified/fixed within the method before being stored. Maybe some data cannot be - * edited based on permissions - * * Method is only called on the instance that owns the shared item * * @param string $itemId * @param array $extraData * @param FederatedUser $federatedUser * - * @return bool + * @return array */ public function isItemUpdatable( string $itemId, array $extraData, - FederatedUser $federatedUser - ): bool; + IFederatedUser $federatedUser + ): array; + } diff --git a/lib/Model/Debug.php b/lib/Model/Debug.php index a98cad2b7..f6cf5f700 100644 --- a/lib/Model/Debug.php +++ b/lib/Model/Debug.php @@ -31,8 +31,6 @@ namespace OCA\Circles\Model; -use JetBrains\PhpStorm\ArrayShape; -use JetBrains\PhpStorm\Pure; use JsonSerializable; use OCA\Circles\Tools\Db\IQueryRow; use OCA\Circles\Tools\Exceptions\InvalidItemException; diff --git a/lib/Model/SyncedItem.php b/lib/Model/SyncedItem.php index 34e878e3c..3a83072ed 100644 --- a/lib/Model/SyncedItem.php +++ b/lib/Model/SyncedItem.php @@ -219,7 +219,7 @@ public function getChecksum(): string { * * @return SyncedItem */ - public function setSerialized(array $serialized): self { + public function setSerialized(array $serialized = []): self { $this->serialized = $serialized; return $this; diff --git a/lib/Model/SyncedWrapper.php b/lib/Model/SyncedWrapper.php new file mode 100644 index 000000000..e4d4081a5 --- /dev/null +++ b/lib/Model/SyncedWrapper.php @@ -0,0 +1,206 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Model; + +use JsonSerializable; +use OCA\Circles\IFederatedUser; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; +use OCA\Circles\Tools\Traits\TArrayTools; +use OCA\Circles\Tools\Traits\TDeserialize; + +class SyncedWrapper implements IReferencedObject, JsonSerializable { + use TArrayTools; + use TDeserialize; + + private ?IFederatedUser $federatedUser; + private ?SyncedItem $item; + private ?SyncedShare $share; + private array $extraData; + + public function __construct( + ?IFederatedUser $federatedUser = null, + ?SyncedItem $item = null, + ?SyncedShare $share = null, + array $extraData = [] + ) { + $this->federatedUser = $federatedUser; + $this->item = $item; + $this->share = $share; + $this->extraData = $extraData; + } + + + /** + * @param IFederatedUser $federatedUser + * + * @return SyncedWrapper + */ + public function setFederatedUser(IFederatedUser $federatedUser): self { + $this->federatedUser = $federatedUser; + + return $this; + } + + /** + * @return bool + */ + public function hasFederatedUser(): bool { + return !is_null($this->federatedUser); + } + + /** + * @return IFederatedUser + */ + public function getFederatedUser(): ?IFederatedUser { + return $this->federatedUser; + } + + + /** + * @param SyncedItem $item + * + * @return SyncedWrapper + */ + public function setItem(SyncedItem $item): self { + $this->item = $item; + + return $this; + } + + /** + * @return bool + */ + public function hasItem(): bool { + return !is_null($this->item); + } + + /** + * @return SyncedItem + */ + public function getItem(): ?SyncedItem { + return $this->item; + } + + + /** + * @param SyncedShare $share + * + * @return SyncedWrapper + */ + public function setShare(SyncedShare $share): self { + $this->share = $share; + + return $this; + } + + /** + * @return bool + */ + public function hasShare(): bool { + return !is_null($this->share); + } + + /** + * @return SyncedShare + */ + public function getShare(): ?SyncedShare { + return $this->share; + } + + + /** + * @param array $extraData + * + * @return SyncedWrapper + */ + public function setExtraData(array $extraData): self { + $this->extraData = $extraData; + + return $this; + } + + /** + * @return array + */ + public function getExtraData(): array { + return $this->extraData; + } + + + /** + * @param array $data + * + * @return ShareToken + */ + public function import(array $data): IDeserializable { + // TODO: use ReferencedDataStore + try { + /** @var IFederatedUser $user */ + $user = $this->deserialize($this->getArray('federatedUser', $data), FederatedUser::class); + $this->setFederatedUser($user); + } catch (InvalidItemException $e) { + } + + try { + /** @var SyncedItem $item */ + $item = $this->deserialize($this->getArray('item', $data), SyncedItem::class); + $this->setItem($item); + } catch (InvalidItemException $e) { + } + + try { + /** @var SyncedShare $share */ + $share = $this->deserialize($this->getArray('share', $data), SyncedShare::class); + $this->setShare($share); + } catch (InvalidItemException $e) { + } + + $this->setExtraData($this->getArray('extraData', $data)); + + return $this; + } + + + /** + * @return array + */ + public function jsonSerialize(): array { + return [ + 'federatedUser' => $this->getFederatedUser(), + 'item' => $this->getItem(), + 'share' => $this->getShare(), + 'extraData' => $this->getExtraData() + ]; + } +} diff --git a/lib/Service/FederatedSyncItemService.php b/lib/Service/FederatedSyncItemService.php index fa6170956..f10f52d37 100644 --- a/lib/Service/FederatedSyncItemService.php +++ b/lib/Service/FederatedSyncItemService.php @@ -31,23 +31,35 @@ namespace OCA\Circles\Service; use Exception; +use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\RemoteRequest; use OCA\Circles\Db\SyncedItemRequest; use OCA\Circles\Db\SyncedShareRequest; +use OCA\Circles\Exceptions\FederatedEventException; use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Exceptions\FederatedSyncConflictException; use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; +use OCA\Circles\Exceptions\InitiatorNotConfirmedException; use OCA\Circles\Exceptions\InvalidIdException; +use OCA\Circles\Exceptions\OwnerNotFoundException; use OCA\Circles\Exceptions\RemoteInstanceException; use OCA\Circles\Exceptions\RemoteNotFoundException; use OCA\Circles\Exceptions\RemoteResourceNotFoundException; +use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\Exceptions\UnknownRemoteException; +use OCA\Circles\FederatedItems\FederatedSync\ItemUpdate; +use OCA\Circles\IFederatedUser; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Model\SyncedShare; +use OCA\Circles\Model\SyncedWrapper; use OCA\Circles\Tools\ActivityPub\NCSignature; use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\Model\Request; +use OCA\Circles\Tools\Model\SimpleDataStore; use OCA\Circles\Tools\Traits\TDeserialize; use OCA\Circles\Tools\Traits\TStringTools; @@ -57,6 +69,7 @@ class FederatedSyncItemService extends NCSignature { private SyncedItemRequest $syncedItemRequest; private SyncedShareRequest $syncedShareRequest; + private CircleRequest $circleRequest; private RemoteRequest $remoteRequest; private FederatedSyncService $federatedSyncService; private FederatedEventService $federatedEventService; @@ -78,6 +91,7 @@ class FederatedSyncItemService extends NCSignature { public function __construct( SyncedItemRequest $syncedItemRequest, SyncedShareRequest $syncedShareRequest, + CircleRequest $circleRequest, RemoteRequest $remoteRequest, FederatedSyncService $federatedSyncService, FederatedEventService $federatedEventService, @@ -87,6 +101,7 @@ public function __construct( ) { $this->syncedItemRequest = $syncedItemRequest; $this->syncedShareRequest = $syncedShareRequest; + $this->circleRequest = $circleRequest; $this->remoteRequest = $remoteRequest; $this->federatedSyncService = $federatedSyncService; $this->federatedEventService = $federatedEventService; @@ -171,6 +186,28 @@ public function getLocalSyncedItem(string $singleId, bool $serializeItem = false return $item; } +// +// /** +// * @param string $singleId +// * @param bool $serializeItem +// * +// * @return SyncedItem +// * @throws FederatedSyncConflictException +// * @throws FederatedSyncManagerNotFoundException +// * @throws SyncedItemNotFoundException +// */ +// public function getSyncedItem(string $singleId, bool $serializeItem = false): SyncedItem { +// $item = $this->syncedItemRequest->getSyncedItemFromSingleId($singleId); +// +// if ($serializeItem) { +// $item->setSerialized( +// $this->federatedSyncService->initSyncManager($item) +// ->serializeItem($item->getItemId()) +// ); +// } +// +// return $item; +// } /** * get existing SyncedItem based appId, itemType and itemId. @@ -190,7 +227,11 @@ public function getLocalSyncedItem(string $singleId, bool $serializeItem = false * @throws FederatedSyncConflictException * @throws FederatedSyncManagerNotFoundException */ - public function getSyncedItem(string $appId, string $itemType, string $itemId): SyncedItem { + public function initSyncedItem( + string $appId, + string $itemType, + string $itemId + ): SyncedItem { // verify existing SyncedItem is not flag as deleted try { @@ -229,6 +270,178 @@ public function getSyncedItem(string $appId, string $itemType, string $itemId): } + public function requestSyncedItemUpdate( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + array $extraData = [] + ): array { + // confirm item is local + if ($syncedItem->isLocal()) { + return $this->requestSyncedItemUpdateLocal($federatedUser, $syncedItem, $extraData); + } else { + return $this->requestSyncedItemUpdateRemote($federatedUser, $syncedItem, $extraData); + } + } + + /** + * @param IFederatedUser $federatedUser + * @param SyncedItem $syncedItem + * @param array $extraData + * + * @return SyncedItem + * @throws FederatedEventException + * @throws FederatedItemException + * @throws FederatedSyncManagerNotFoundException + * @throws InitiatorNotConfirmedException + * @throws OwnerNotFoundException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException + */ + private function requestSyncedItemUpdateLocal( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + array $extraData = [] + ): array { + $item = $this->isItemUpdatable($federatedUser, $syncedItem, $extraData); + + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + $syncManager->syncItem( + $syncedItem->getItemId(), + $item + ); + + $this->updateChecksum($syncedItem->getSingleId()); + + // broadcast update signal + // TODO: if request origin is not local, Async here, return $item to the remote instance + $this->broadcastItemUpdate($syncedItem->getSingleId()); + +// $syncedItem->setSerialized($item); + + return $item; + +// +// try { +// $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); +// } catch (SyncedItemNotFoundException $e) { +// $this->debugService->info( +// 'storing SyncedItem {syncedItem.singleId} in database', '', +// ['syncedItem' => $syncedItem] +// ); +// +// $this->syncedItemRequest->save($syncedItem); +// } +// +// $this->syncShareCreation($syncedItem, $circle, $extraData); +// $this->broadcastShareCreation($syncedItem, $circle, $extraData); +// +// $this->debugService->info( +// 'SyncedShare created and FederatedSync is on its way; {~end of main process}' +// ); + + } + + + private function requestSyncedItemUpdateRemote( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + array $extraData = [] + ): array { + $wrapper = new SyncedWrapper($federatedUser, $syncedItem, null, $extraData); + $this->interfaceService->setCurrentInterfaceFromInstance($syncedItem->getInstance()); + $data = $this->remoteStreamService->resultRequestRemoteInstance( + $syncedItem->getInstance(), + RemoteInstance::SYNC_ITEM, + Request::TYPE_PUT, + $wrapper + ); + + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + $syncManager->syncItem( + $syncedItem->getItemId(), + $data + ); + + $this->updateChecksum($syncedItem->getSingleId(), $data); + + return $data; + } + + + private function updateChecksum(string $syncedItemId, ?array $data = null): void { + $currSum = ''; + if (is_null($data)) { + $knownItem = $this->getLocalSyncedItem($syncedItemId, true); + $data = $knownItem->getSerialized(); + $currSum = $knownItem->getChecksum(); + } + + $sum = md5(json_encode($data)); + if ($sum === $currSum) { + return; + } + + $this->syncedItemRequest->updateChecksum($syncedItemId, $sum); + } + + /** + * @param Circle $circle + * @param SyncedItem $syncedItem + * + * @throws FederatedEventException + * @throws FederatedItemException + * @throws InitiatorNotConfirmedException + * @throws OwnerNotFoundException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException + */ + private function broadcastItemUpdate(string $singleId): void { + $syncedItem = $this->syncedItemRequest->getSyncedItemFromSingleId($singleId); + + foreach ($this->getAffectedCircles($singleId) as $circle) { + $event = new FederatedEvent(ItemUpdate::class); + $event->setCircle($circle) + ->setSyncedItem($syncedItem); + + $this->debugService->info( + 'generating {`IFederatedEvent} using {event.class}', + $circle->getSingleId(), + [ + 'event' => $event, + 'syncedItem' => $syncedItem, + 'circle' => $circle + ] + ); + + // TODO: do not async for each circle as it should already on a async process! + $this->federatedEventService->newEvent($event); + } + } + + + /** + * @param string $singleId + * + * @return Circle[] + * @throws RequestBuilderException + */ + private function getAffectedCircles(string $singleId): array { + $circleIds = array_map( + function (SyncedShare $share): string { + return $share->getCircleId(); + }, $this->syncedShareRequest->getshares($singleId) + ); + + return $this->circleRequest->getCirclesByIds($circleIds); + } + + /** * create a new (local) SyncedItem based on appId, itemType, itemId. * @@ -251,6 +464,19 @@ private function createSyncedItem(string $appId, string $itemType, string $itemI ['syncedItem' => $syncedItem] ); +// try { +// $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); +// } catch (SyncedItemNotFoundException $e) { + $this->debugService->info( + 'storing SyncedItem {syncedItem.singleId} in database', '', + ['syncedItem' => $syncedItem] + ); + + $this->syncedItemRequest->save($syncedItem); + +// } + + return $syncedItem; } @@ -336,4 +562,150 @@ public function updateSyncedItem(SyncedItem $syncedItem): void { $this->syncedItemRequest->save($remoteItem); } + + + /** + * @param IFederatedUser $federatedUser + * @param SyncedItem $syncedItem + * @param array $extraData + * + * @return array + * @throws FederatedSyncManagerNotFoundException + */ + private function isItemUpdatable( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + array $extraData = [] + ): array { + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + $this->debugService->info( + 'sharing of SyncedItem {syncedItem.singleId} looks doable, calling {`isShareCreatable()} on {syncManager.class} for confirmation', + '', + [ + 'federatedUser' => $federatedUser, + 'syncedItem' => $syncedItem, + 'syncManager' => ['class' => get_class($syncManager)] + ] + ); + + try { + return $syncManager->isItemUpdatable( + $syncedItem->getItemId(), + $extraData, + $federatedUser + ); + } catch (Exception $e) { + $this->debugService->exception($e); +// $this->debugService->info( +// 'update of SyncedItem {!syncedItem.singleId} is blocked by {!syncedItem.appId}', +// '', +// [ +// 'federatedUser' => $federatedUser, +// 'syncedItem' => $syncedItem, +// 'extraData' => $extraData +// ] +// ); + // define Exception that can be thrown by app: + // - itemnotfound + // - ItemUpdateException + // + throw $e; + } + } + + + /** + * @param SyncedItem $syncedItem + * + * @throws FederatedSyncConflictException + */ + public function compareWithKnownItem( + SyncedItem $syncedItem, + bool $allowUnknownItem = false + ): void { + try { + $this->compareWithKnownItemId($syncedItem); + $this->compareWithKnownSingleId($syncedItem); + } catch (FederatedSyncConflictException $e) { + $this->debugService->exception( + $e, '', + [ + 'note' => 'WIP: exception is thrown and catch to async process; while returning error', + 'note2' => 'async process will try to fix the conflict' + ] + ); + // TODO: manage FederatedSyncConflictException - should not be run 'live' at this point + // The solution might be to Async the current process with an error while fixing the issue + // on the child process. remote instance will tell the initiator that there is an issue and + // he should try again (estimating the process to fix conflict might takes few seconds. + // To do so, catching the exception earlier instead of here. + throw $e; + } catch (SyncedItemNotFoundException $e) { + if (!$allowUnknownItem) { + throw $e; + } + + $this->debugService->info( + 'no known syncedItem {syncedItem.singleId} were found in database, assuming this is good', + '', + ['syncedItem' => $syncedItem] + ); + } + } + + + /** + * @throws FederatedSyncConflictException + * @throws SyncedItemNotFoundException + */ + private function compareWithKnownSingleId(SyncedItem $syncedItem): void { + $knownItem = $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); + $this->debugService->info( + 'Comparing with the SyncedItem {syncedItem.singleId} from database: {knownItem.appId}.{knownItem.itemType}.{knownItem.itemId}', + '', + [ + 'syncedItem' => $syncedItem, + 'knownItem' => $knownItem + ] + ); + + if ($knownItem->getAppId() !== $syncedItem->getAppId() + || $knownItem->getItemType() !== $syncedItem->getItemType() + || $knownItem->getInstance() !== $syncedItem->getInstance() + || $knownItem->isDeleted()) { + throw new FederatedSyncConflictException('conflict/dsync on SyncedItem'); + } + } + + + /** + * @param SyncedItem $syncedItem + * + * @throws FederatedSyncConflictException + */ + private function compareWithKnownItemId(SyncedItem $syncedItem): void { + try { + $knownItem = $this->syncedItemRequest->getSyncedItem( + $syncedItem->getAppId(), + $syncedItem->getItemType(), + $syncedItem->getItemId() + ); + } catch (SyncedItemNotFoundException $e) { + return; + } + + $this->debugService->info( + 'Comparing with the SyncedItem {syncedItem.appId}.{syncedItem.itemType}.{syncedItem.itemId} from database: {knownItem.singleId}', + '', + [ + 'syncedItem' => $syncedItem, + 'knownItem' => $knownItem + ] + ); + + if ($knownItem->getSingleId() !== $syncedItem->getSingleId()) { + throw new FederatedSyncConflictException('conflict/dsync on SyncedItem'); + } + } + } diff --git a/lib/Service/FederatedSyncService.php b/lib/Service/FederatedSyncService.php index 2ae6e10d1..282b84712 100644 --- a/lib/Service/FederatedSyncService.php +++ b/lib/Service/FederatedSyncService.php @@ -35,10 +35,8 @@ use OCA\Circles\Db\SyncedShareRequest; use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; use OCA\Circles\IFederatedSyncManager; -use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\SyncedItem; use OCA\Circles\Tools\ActivityPub\NCSignature; -use OCA\Circles\Tools\Model\Request; use OCA\Circles\Tools\Traits\TStringTools; class FederatedSyncService extends NCSignature { @@ -118,22 +116,9 @@ public function initSyncManager(SyncedItem $syncedItem): IFederatedSyncManager { } + public function broadcastToItemRecipients() { - // - public function reachInstance(string $instance) { -// $remoteInstance = $this->remoteRequest->getFromInstance($instance); - $syncedItem = new SyncedItem(); - $syncedItem->setSingleId('toto'); - -// $this->interfaceService->setCurrentInterface($remoteInstance->getInterface()); - $data = $this->remoteStreamService->resultRequestRemoteInstance( - $instance, - RemoteInstance::SYNC_ITEM, - Request::TYPE_POST, - $syncedItem - ); - - echo 'reached !? ' . json_encode($data) . "\n"; } + } diff --git a/lib/Service/FederatedSyncShareService.php b/lib/Service/FederatedSyncShareService.php index fe7e55eb8..9fa323ca8 100644 --- a/lib/Service/FederatedSyncShareService.php +++ b/lib/Service/FederatedSyncShareService.php @@ -126,17 +126,6 @@ public function createShare(SyncedItem $syncedItem, Circle $circle, array $extra ); } - try { - $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); - } catch (SyncedItemNotFoundException $e) { - $this->debugService->info( - 'storing SyncedItem {syncedItem.singleId} in database', '', - ['syncedItem' => $syncedItem] - ); - - $this->syncedItemRequest->save($syncedItem); - } - $this->syncShareCreation($syncedItem, $circle, $extraData); $this->broadcastShareCreation($syncedItem, $circle, $extraData); diff --git a/lib/Service/ShareWrapperService.php b/lib/Service/ShareWrapperService.php index 17bd1c6f2..a39ec7cd1 100644 --- a/lib/Service/ShareWrapperService.php +++ b/lib/Service/ShareWrapperService.php @@ -227,7 +227,7 @@ public function getSharedWith( throw new InvalidItemException(); } - return $this->deserializeArray($cachedData, ShareWrapper::class); + return $this->deserializeArrayFromJson($cachedData, ShareWrapper::class); } catch (InvalidItemException $e) { } diff --git a/lib/Service/SignedControllerService.php b/lib/Service/SignedControllerService.php index e48a53f66..990cfd203 100644 --- a/lib/Service/SignedControllerService.php +++ b/lib/Service/SignedControllerService.php @@ -90,20 +90,22 @@ class SignedControllerService { protected InterfaceService $interfaceService; protected FederatedUserService $federatedUserService; protected ConfigService $configService; - + protected DebugService $debugService; public function __construct( IUserSession $userSession, FederatedUserService $federatedUserService, InterfaceService $interfaceService, RemoteStreamService $remoteStreamService, - ConfigService $configService + ConfigService $configService, + DebugService $debugService ) { $this->remoteStreamService = $remoteStreamService; $this->interfaceService = $interfaceService; $this->federatedUserService = $federatedUserService; $this->configService = $configService; + $this->debugService = $debugService; } diff --git a/lib/Tools/Model/ReferencedDataStore.php b/lib/Tools/Model/ReferencedDataStore.php index 0dc2ab7a0..b74c1ce3e 100644 --- a/lib/Tools/Model/ReferencedDataStore.php +++ b/lib/Tools/Model/ReferencedDataStore.php @@ -31,7 +31,6 @@ namespace OCA\Circles\Tools\Model; -use JetBrains\PhpStorm\Pure; use JsonSerializable; use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\Exceptions\ItemNotFoundException; @@ -326,7 +325,6 @@ public function hasKey(string $key): bool { * * @return bool */ - #[Pure] public function hasKeys(array $keys): bool { foreach ($keys as $key) { if (!$this->hasKey($key)) { diff --git a/lib/Tools/Traits/TDeserialize.php b/lib/Tools/Traits/TDeserialize.php index 82020e35c..39905803f 100644 --- a/lib/Tools/Traits/TDeserialize.php +++ b/lib/Tools/Traits/TDeserialize.php @@ -82,17 +82,29 @@ public function deserialize(array $data, string $class): IDeserializable { * @param string $class * * @return IDeserializable[] - * @throws InvalidItemException */ - public function deserializeArray(string $json, string $class): array { - $arr = []; + public function deserializeArrayFromJson(string $json, string $class): array { $data = json_decode($json, true); if (!is_array($data)) { - return $arr; + return []; } + return $this->deserializeArray($data, $class); + } + + /** + * @param array $data + * @param string $class + * + * @return array + */ + public function deserializeArray(array $data, string $class): array { + $arr = []; foreach ($data as $entry) { - $arr[] = $this->deserialize($entry, $class); + try { + $arr[] = $this->deserialize($entry, $class); + } catch (InvalidItemException $e) { + } } return $arr; From 52f61bccb70135246ec30182991bf79242afde36 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Tue, 31 May 2022 11:07:07 -0100 Subject: [PATCH 3/5] async/split on demand, and only if required Signed-off-by: Maxence Lange --- appinfo/routes.php | 5 +- lib/CircleSharesManager.php | 32 +- lib/Controller/EventWrapperController.php | 46 ++- lib/Controller/SyncController.php | 23 +- lib/Db/CoreQueryBuilder.php | 54 +-- lib/Db/CoreRequestBuilder.php | 3 +- lib/Db/EventWrapperRequest.php | 36 +- lib/Db/SyncedItemLockRequest.php | 50 ++- .../FederatedSyncConflictException.php | 22 +- lib/Exceptions/FederatedSyncException.php | 96 +++++ .../FederatedSyncPermissionException.php | 47 +++ .../FederatedSyncRequestException.php | 54 +++ lib/Exceptions/InternalAsyncException.php | 37 ++ lib/Exceptions/SyncedItemLockException.php | 47 +++ .../SyncedItemNotFoundException.php | 15 +- .../SyncedShareNotFoundException.php | 13 + .../SyncedSharedAlreadyExistException.php | 15 +- lib/ICircleSharesManager.php | 8 +- lib/IFederatedSyncManager.php | 31 +- lib/IInternalAsync.php | 42 +++ lib/InternalAsync/AsyncItemUpdate.php | 187 ++++++++++ lib/InternalAsync/AsyncTest.php | 63 ++++ .../Version0025Date20220510104622.php | 36 +- lib/Model/Federated/EventWrapper.php | 138 ++++++-- lib/Model/FederatedUser.php | 12 +- lib/Model/SyncedItemLock.php | 51 ++- lib/Model/SyncedWrapper.php | 37 ++ lib/Service/AsyncService.php | 258 ++++++++++++++ lib/Service/EventWrapperService.php | 60 +++- lib/Service/FederatedEventService.php | 50 +-- lib/Service/FederatedSyncItemService.php | 334 ++++++++++-------- lib/Service/GSUpstreamService.php | 4 +- lib/Service/RemoteStreamService.php | 6 +- lib/Service/RemoteUpstreamService.php | 16 +- lib/Tools/Model/ReferencedDataStore.php | 12 +- lib/Tools/Traits/TAsync.php | 4 +- 36 files changed, 1577 insertions(+), 367 deletions(-) create mode 100644 lib/Exceptions/FederatedSyncException.php create mode 100644 lib/Exceptions/FederatedSyncPermissionException.php create mode 100644 lib/Exceptions/FederatedSyncRequestException.php create mode 100644 lib/Exceptions/InternalAsyncException.php create mode 100644 lib/Exceptions/SyncedItemLockException.php create mode 100644 lib/IInternalAsync.php create mode 100644 lib/InternalAsync/AsyncItemUpdate.php create mode 100644 lib/InternalAsync/AsyncTest.php create mode 100644 lib/Service/AsyncService.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 2ce2639a0..91b835234 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -101,7 +101,8 @@ ], 'routes' => [ - ['name' => 'EventWrapper#asyncBroadcast', 'url' => '/async/{token}/', 'verb' => 'POST'], + ['name' => 'EventWrapper#asyncBroadcast', 'url' => '/async/broadcast/{token}', 'verb' => 'POST'], + ['name' => 'EventWrapper#asyncInternal', 'url' => '/async/internal/{token}', 'verb' => 'POST'], ['name' => 'Remote#appService', 'url' => '/', 'verb' => 'GET'], ['name' => 'Remote#test', 'url' => '/test', 'verb' => 'GET'], @@ -114,7 +115,7 @@ ['name' => 'Remote#inherited', 'url' => '/inherited/{circleId}/', 'verb' => 'GET'], ['name' => 'Remote#memberships', 'url' => '/memberships/{circleId}/', 'verb' => 'GET'], - ['name' => 'Sync#getSyncedItem', 'url' => '/sync/item', 'verb' => 'GET'], + ['name' => 'Sync#syncItem', 'url' => '/sync/item', 'verb' => 'GET'], ['name' => 'Sync#updateSyncedItem', 'url' => '/sync/item', 'verb' => 'PUT'], // ['name' => 'Remote#syncItem', 'url' => '/sync/item/{singleId}', 'verb' => 'GET'], ['name' => 'Sync#syncShare', 'url' => '/sync/share', 'verb' => 'POST'], diff --git a/lib/CircleSharesManager.php b/lib/CircleSharesManager.php index f5729e53f..59973b4d9 100644 --- a/lib/CircleSharesManager.php +++ b/lib/CircleSharesManager.php @@ -34,6 +34,7 @@ use Exception; use OCA\Circles\Exceptions\CircleSharesManagerException; use OCA\Circles\Model\Probes\CircleProbe; +use OCA\Circles\Model\SyncedItemLock; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\DebugService; @@ -208,13 +209,30 @@ public function deleteShare(string $itemId, string $circleId): void { /** * @param string $itemId + * @param string $updateType + * @param string $updateTypeId * @param array $extraData + * @param bool $sumCheck * * @throws CircleSharesManagerException + * @throws Exceptions\FederatedEventException + * @throws Exceptions\FederatedItemException + * @throws Exceptions\FederatedSyncConflictException + * @throws Exceptions\FederatedSyncManagerNotFoundException + * @throws Exceptions\InitiatorNotConfirmedException + * @throws Exceptions\OwnerNotFoundException + * @throws Exceptions\RemoteInstanceException + * @throws Exceptions\RemoteNotFoundException + * @throws Exceptions\RemoteResourceNotFoundException + * @throws Exceptions\RequestBuilderException + * @throws Exceptions\UnknownRemoteException */ public function updateItem( string $itemId, - array $extraData = [] + string $updateType = '', + string $updateTypeId = '', + array $extraData = [], + bool $sumCheck = true ): void { $this->mustHaveOrigin(); @@ -226,20 +244,13 @@ public function updateItem( 'appId' => $this->originAppId, 'itemType' => $this->originItemType, 'itemId' => $itemId, + 'updateType' => $updateType, + 'updateTypeId' => $updateTypeId, 'extraData' => $extraData ] ); try { -// $this->mustHaveOrigin(); - -// // TODO: verify rules that apply when sharing to a circle -// $probe = new CircleProbe(); -// $probe->includeSystemCircles() -// ->mustBeMember(); -// -// $circle = $this->circleService->getCircle($circleId, $probe); -// // get valid SyncedItem based on appId, itemType, itemId $syncedItem = $this->federatedSyncItemService->initSyncedItem( $this->originAppId, @@ -260,6 +271,7 @@ public function updateItem( $this->federatedSyncItemService->requestSyncedItemUpdate( $this->federatedUserService->getCurrentEntity(), $syncedItem, + new SyncedItemLock($updateType, $updateTypeId, $sumCheck), $extraData ); } catch (Exception $e) { diff --git a/lib/Controller/EventWrapperController.php b/lib/Controller/EventWrapperController.php index fd2ca5a84..9bae8731b 100644 --- a/lib/Controller/EventWrapperController.php +++ b/lib/Controller/EventWrapperController.php @@ -32,6 +32,8 @@ namespace OCA\Circles\Controller; use OCA\Circles\AppInfo\Application; +use OCA\Circles\Exceptions\EventWrapperNotFoundException; +use OCA\Circles\Service\AsyncService; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\EventWrapperService; use OCA\Circles\Service\FederatedEventService; @@ -66,6 +68,8 @@ class EventWrapperController extends Controller { /** @var RemoteDownstreamService */ private $remoteDownstreamService; + private AsyncService $asyncService; + /** @var ConfigService */ private $configService; @@ -79,6 +83,7 @@ class EventWrapperController extends Controller { * @param FederatedEventService $federatedEventService * @param RemoteUpstreamService $remoteUpstreamService * @param RemoteDownstreamService $remoteDownstreamService + * @param AsyncService $asyncService * @param ConfigService $configService */ public function __construct( @@ -88,6 +93,7 @@ public function __construct( FederatedEventService $federatedEventService, RemoteUpstreamService $remoteUpstreamService, RemoteDownstreamService $remoteDownstreamService, + AsyncService $asyncService, ConfigService $configService ) { parent::__construct($appName, $request); @@ -95,6 +101,7 @@ public function __construct( $this->federatedEventService = $federatedEventService; $this->remoteUpstreamService = $remoteUpstreamService; $this->remoteDownstreamService = $remoteDownstreamService; + $this->asyncService = $asyncService; $this->configService = $configService; $this->setup('app', Application::APP_ID); @@ -105,7 +112,7 @@ public function __construct( /** * Called locally. * - * Async process and broadcast the event to every instances of GS + * Async process and broadcast the event to every instance of GS * This should be initiated by the instance that owns the Circles. * * @PublicPage @@ -116,19 +123,15 @@ public function __construct( * @return DataResponse */ public function asyncBroadcast(string $token): DataResponse { - $wrappers = $this->remoteUpstreamService->getEventsByToken($token); + $wrappers = $this->eventWrapperService->getBroadcastByToken($token); if (empty($wrappers) && $token !== 'test-dummy-token') { return new DataResponse([], Http::STATUS_OK); } // closing socket, keep current process running. - $this->async(); - - foreach ($wrappers as $wrapper) { - $this->eventWrapperService->manageWrapper($wrapper); - } - - $this->eventWrapperService->confirmStatus($token); + $this->asyncService->setSplittable(true); + $this->asyncService->split(); + $this->eventWrapperService->performBroadcast($token, $wrappers); // so circles:check can check async is fine if ($token === 'test-dummy-token') { @@ -140,6 +143,31 @@ public function asyncBroadcast(string $token): DataResponse { } + /** + * Called locally. + * + * Async process and continue using IInternalAsync + * + * @PublicPage + * @NoCSRFRequired + * + * @param string $token + * + * @return DataResponse + * @throws EventWrapperNotFoundException + */ + public function asyncInternal(string $token): DataResponse { + $this->asyncService->setSplittable(true); + $this->asyncService->split(); + + $this->eventWrapperService->performInternal($token); + + // exit() or useless log will be generated + exit(); + } + + + // /** // * Status Event. This is an event to check status of items between instances. // * diff --git a/lib/Controller/SyncController.php b/lib/Controller/SyncController.php index 37b6f1a55..fd1f82dc6 100644 --- a/lib/Controller/SyncController.php +++ b/lib/Controller/SyncController.php @@ -35,6 +35,7 @@ use OCA\Circles\Exceptions\FederatedItemBadRequestException; use OCA\Circles\Model\SyncedItem; use OCA\Circles\Model\SyncedWrapper; +use OCA\Circles\Service\AsyncService; use OCA\Circles\Service\DebugService; use OCA\Circles\Service\FederatedSyncItemService; use OCA\Circles\Service\FederatedSyncShareService; @@ -54,6 +55,7 @@ class SyncController extends Controller { private FederatedSyncItemService $federatedSyncItemService; private FederatedSyncShareService $federatedSyncShareService; private DebugService $debugService; + private AsyncService $asyncService; public function __construct( string $appName, @@ -61,6 +63,7 @@ public function __construct( SignedControllerService $signedControllerService, FederatedSyncItemService $federatedSyncItemService, FederatedSyncShareService $federatedSyncShareService, + AsyncService $asyncService, DebugService $debugService ) { parent::__construct($appName, $request); @@ -68,6 +71,7 @@ public function __construct( $this->signedControllerService = $signedControllerService; $this->federatedSyncItemService = $federatedSyncItemService; $this->federatedSyncShareService = $federatedSyncShareService; + $this->asyncService = $asyncService; $this->debugService = $debugService; } @@ -78,7 +82,7 @@ public function __construct( * * @return DataResponse */ - public function getSyncedItem(): DataResponse { + public function syncItem(): DataResponse { try { /** @var SyncedItem $item */ $item = $this->signedControllerService->extractObjectFromRequest( @@ -145,8 +149,8 @@ public function updateSyncedItem(): DataResponse { throw new FederatedItemBadRequestException(); } - $item = $wrapper->getItem(); - $local = $this->federatedSyncItemService->getLocalSyncedItem($item->getSingleId()); + $syncedItem = $wrapper->getItem(); + $local = $this->federatedSyncItemService->getLocalSyncedItem($syncedItem->getSingleId()); // confirm that remote is in a circle with a share on the item $this->federatedSyncShareService->confirmRemoteInstanceAccess( @@ -162,18 +166,25 @@ public function updateSyncedItem(): DataResponse { ] ); - $updated = $this->federatedSyncItemService->requestSyncedItemUpdate( + $this->asyncService->setSplittable(true); + $this->federatedSyncItemService->requestSyncedItemUpdate( $wrapper->getFederatedUser(), $local, - $wrapper->getExtraData() + $wrapper->getLock(), + $wrapper->getExtraData(), + $syncedItem->getChecksum() ); - return new DataResponse($updated); + if (!$this->asyncService->isAsynced()) { + return new DataResponse(['success' => true]); + } } catch (Exception $e) { $this->e($e); return $this->signedControllerService->exceptionResponse($e, Http::STATUS_UNAUTHORIZED); } + + exit(); } } diff --git a/lib/Db/CoreQueryBuilder.php b/lib/Db/CoreQueryBuilder.php index 5297f0601..bd1b803ac 100644 --- a/lib/Db/CoreQueryBuilder.php +++ b/lib/Db/CoreQueryBuilder.php @@ -56,33 +56,33 @@ class CoreQueryBuilder extends ExtendedQueryBuilder { use TArrayTools; - public const SINGLE = 'cs'; - public const CIRCLE = 'cc'; - public const MEMBER = 'mm'; - public const OWNER = 'wn'; - public const FEDERATED_EVENT = 'ev'; - public const REMOTE = 'rm'; - public const BASED_ON = 'on'; - public const INITIATOR = 'in'; - public const DIRECT_INITIATOR = 'di'; - public const MEMBERSHIPS = 'ms'; - public const CONFIG = 'cf'; - public const UPSTREAM_MEMBERSHIPS = 'up'; - public const INHERITANCE_FROM = 'ih'; - public const INHERITED_BY = 'by'; - public const INVITED_BY = 'nv'; - public const MOUNT = 'mo'; - public const MOUNTPOINT = 'mp'; - public const SHARE = 'sh'; - public const FILE_CACHE = 'fc'; - public const STORAGES = 'st'; - public const TOKEN = 'tk'; - public const OPTIONS = 'pt'; - public const HELPER = 'hp'; - public const SYNC_ITEM = 'si'; - public const SYNC_SHARE = 'ss'; - public const SYNC_LOCK = 'sl'; - public const DEBUG = 'bg'; + public const SINGLE = 'ca'; + public const CIRCLE = 'cb'; + public const MEMBER = 'cc'; + public const OWNER = 'cd'; + public const FEDERATED_EVENT = 'ce'; + public const REMOTE = 'cf'; + public const BASED_ON = 'cg'; + public const INITIATOR = 'ch'; + public const DIRECT_INITIATOR = 'ci'; + public const MEMBERSHIPS = 'cj'; + public const CONFIG = 'ck'; + public const UPSTREAM_MEMBERSHIPS = 'cl'; + public const INHERITANCE_FROM = 'cm'; + public const INHERITED_BY = 'cn'; + public const INVITED_BY = 'co'; + public const MOUNT = 'cp'; + public const MOUNTPOINT = 'cq'; + public const SHARE = 'cr'; + public const FILE_CACHE = 'cs'; + public const STORAGES = 'ct'; + public const TOKEN = 'cu'; + public const OPTIONS = 'cv'; + public const HELPER = 'cw'; + public const SYNC_ITEM = 'cx'; + public const SYNC_SHARE = 'cy'; + public const SYNC_LOCK = 'cz'; + public const DEBUG = 'c0'; public static $SQL_PATH = [ diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index 6101dbc1c..ab4f01473 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -124,6 +124,8 @@ class CoreRequestBuilder { self::TABLE_EVENT => [ 'token', 'event', + 'store', + 'event_type', 'result', 'instance', 'interface', @@ -160,7 +162,6 @@ class CoreRequestBuilder { ], self::TABLE_SYNC_LOCK => [ 'id', - 'single_id', 'update_type', 'update_type_id', 'time' diff --git a/lib/Db/EventWrapperRequest.php b/lib/Db/EventWrapperRequest.php index c1d92789f..737e6efad 100644 --- a/lib/Db/EventWrapperRequest.php +++ b/lib/Db/EventWrapperRequest.php @@ -31,6 +31,7 @@ namespace OCA\Circles\Db; +use OCA\Circles\Exceptions\EventWrapperNotFoundException; use OCA\Circles\Model\Federated\EventWrapper; /** @@ -43,15 +44,16 @@ class EventWrapperRequest extends EventWrapperRequestBuilder { /** * @param EventWrapper $wrapper + * + * @throws \OCP\DB\Exception */ public function save(EventWrapper $wrapper): void { $qb = $this->getEventWrapperInsertSql(); $qb->setValue('token', $qb->createNamedParameter($wrapper->getToken())) + ->setValue('event_type', $qb->createNamedParameter($wrapper->getEventType())) ->setValue( - 'event', $qb->createNamedParameter(json_encode($wrapper->getEvent(), JSON_UNESCAPED_SLASHES)) - ) - ->setValue( - 'result', $qb->createNamedParameter(json_encode($wrapper->getResult(), JSON_UNESCAPED_SLASHES)) + 'result', + $qb->createNamedParameter(json_encode($wrapper->getResult(), JSON_UNESCAPED_SLASHES)) ) ->setValue('instance', $qb->createNamedParameter($wrapper->getInstance())) ->setValue('interface', $qb->createNamedParameter($wrapper->getInterface())) @@ -60,7 +62,13 @@ public function save(EventWrapper $wrapper): void { ->setValue('status', $qb->createNamedParameter($wrapper->getStatus())) ->setValue('creation', $qb->createNamedParameter($wrapper->getCreation())); - $qb->execute(); + $event = ($wrapper->hasEvent()) ? json_encode($wrapper->getEvent(), JSON_UNESCAPED_SLASHES) : ''; + $qb->setValue('event', $qb->createNamedParameter($event)); + + $store = ($wrapper->hasStore()) ? json_encode($wrapper->getStore(), JSON_UNESCAPED_SLASHES) : ''; + $qb->setValue('store', $qb->createNamedParameter($store)); + + $qb->executeStatement(); } /** @@ -113,10 +121,26 @@ public function getFailedEvents(array $retryRange): array { * * @return EventWrapper[] */ - public function getByToken(string $token): array { + public function getBroadcastByToken(string $token): array { $qb = $this->getEventWrapperSelectSql(); $qb->limitToToken($token); + $qb->limit('event_type', EventWrapper::TYPE_BROADCAST); return $this->getItemsFromRequest($qb); } + + + /** + * @param string $token + * + * @return EventWrapper + * @throws EventWrapperNotFoundException + */ + public function getInternalByToken(string $token): EventWrapper { + $qb = $this->getEventWrapperSelectSql(); + $qb->limitToToken($token); + $qb->limit('event_type', EventWrapper::TYPE_INTERNAL); + + return $this->getItemFromRequest($qb); + } } diff --git a/lib/Db/SyncedItemLockRequest.php b/lib/Db/SyncedItemLockRequest.php index 19a8ae595..b335ac8d3 100644 --- a/lib/Db/SyncedItemLockRequest.php +++ b/lib/Db/SyncedItemLockRequest.php @@ -32,7 +32,9 @@ namespace OCA\Circles\Db; use OCA\Circles\Exceptions\InvalidIdException; +use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\Model\SyncedItemLock; +use OCA\Circles\Tools\Exceptions\InvalidItemException; /** * Class SyncedItemLockRequest @@ -48,14 +50,52 @@ class SyncedItemLockRequest extends SyncedItemLockRequestBuilder { * @throws InvalidIdException */ public function save(SyncedItemLock $lock): void { - $this->confirmValidIds([$lock->getSingleId()]); - $qb = $this->getSyncedItemLockInsertSql(); - $qb->setValue('single_id', $qb->createNamedParameter($lock->getSingleId())) - ->setValue('update_type', $qb->createNamedParameter($lock->getUpdateType())) + $qb->setValue('update_type', $qb->createNamedParameter($lock->getUpdateType())) ->setValue('update_type_id', $qb->createNamedParameter($lock->getUpdateTypeId())) - ->setValue('time', $qb->createNamedParameter($lock->getTime())); + ->setValue('time', $qb->createNamedParameter(time())); $qb->execute(); } + + + /** + * @param SyncedItemLock $syncedLock + */ + public function remove(SyncedItemLock $syncedLock): void { + $qb = $this->getSyncedItemLockDeleteSql(); + + $qb->limit('update_type', $syncedLock->getUpdateType()); + $qb->limit('update_type_id', $syncedLock->getUpdateTypeId()); + + $qb->executeStatement(); + } + + /** + * @param SyncedItemLock $syncedLock + * + * @return SyncedItemLock + * @throws SyncedItemNotFoundException + * @throws InvalidItemException + */ + public function getSyncedItemLock(SyncedItemLock $syncedLock): SyncedItemLock { + $qb = $this->getSyncedItemLockSelectSql(); + + $qb->limit('update_type', $syncedLock->getUpdateType()); + $qb->limit('update_type_id', $syncedLock->getUpdateTypeId()); + + return $this->getItemFromRequest($qb); + } + + + /** + * @param int $time + */ + public function clean(int $time = 10): void { + $qb = $this->getSyncedItemLockDeleteSql(); + $qb->lt('time', (time() - $time)); + + $qb->executeStatement(); + } + } diff --git a/lib/Exceptions/FederatedSyncConflictException.php b/lib/Exceptions/FederatedSyncConflictException.php index cfac9e77a..75bee9336 100644 --- a/lib/Exceptions/FederatedSyncConflictException.php +++ b/lib/Exceptions/FederatedSyncConflictException.php @@ -30,7 +30,25 @@ namespace OCA\Circles\Exceptions; -use Exception; +use OCP\AppFramework\Http; +use Throwable; -class FederatedSyncConflictException extends FederatedItemConflictException { +class FederatedSyncConflictException extends FederatedSyncException { + public const STATUS = Http::STATUS_CONFLICT; + + /** + * FederatedItemConflictException constructor. + * + * @param string $message + * @param int $code + * @param Throwable|null $previous + */ + public function __construct( + string $message = '', + int $code = 0, + ?Throwable $previous = null + ) { + parent::__construct($message, ($code > 0) ? $code : self::STATUS, $previous); + $this->setStatus(self::STATUS); + } } diff --git a/lib/Exceptions/FederatedSyncException.php b/lib/Exceptions/FederatedSyncException.php new file mode 100644 index 000000000..149821aac --- /dev/null +++ b/lib/Exceptions/FederatedSyncException.php @@ -0,0 +1,96 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Exceptions; + +use Exception; +use JsonSerializable; +use OCP\AppFramework\Http; +use Throwable; + +/** + * Class FederatedItemException + * + * @package OCA\Circles\Exceptions + */ +class FederatedSyncException extends Exception implements JsonSerializable { + public static array $CHILDREN = [ + SyncedItemNotFoundException::class, + SyncedItemLockException::class, + SyncedShareNotFoundException::class, + SyncedSharedAlreadyExistException::class + ]; + + + /** @var int */ + private int $status = Http::STATUS_BAD_REQUEST; + + + /** + * FederatedItemException constructor. + * + * @param string $message + * @param int $code + * @param Throwable|null $previous + */ + public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null) { + parent::__construct($message, ($code > 0) ? $code : $this->status, $previous); + } + + + /** + * @param int $status + */ + protected function setStatus(int $status): void { + $this->status = $status; + } + + /** + * @return int + */ + public function getStatus(): int { + return $this->status; + } + + + /** + * @return array + */ + public function jsonSerialize(): array { + return [ + 'class' => get_class($this), + 'status' => $this->getStatus(), + 'code' => $this->getCode(), + 'message' => $this->getMessage() + ]; + } +} diff --git a/lib/Exceptions/FederatedSyncPermissionException.php b/lib/Exceptions/FederatedSyncPermissionException.php new file mode 100644 index 000000000..7ceb96869 --- /dev/null +++ b/lib/Exceptions/FederatedSyncPermissionException.php @@ -0,0 +1,47 @@ + + * @copyright 2021 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Exceptions; + +use OCP\AppFramework\Http; +use Throwable; + +class FederatedSyncPermissionException extends FederatedSyncException { + public const STATUS = Http::STATUS_METHOD_NOT_ALLOWED; + + public function __construct( + string $message = '', + int $code = 0, + ?Throwable $previous = null + ) { + parent::__construct($message, ($code > 0) ? $code : self::STATUS, $previous); + $this->setStatus(self::STATUS); + } +} diff --git a/lib/Exceptions/FederatedSyncRequestException.php b/lib/Exceptions/FederatedSyncRequestException.php new file mode 100644 index 000000000..fe8da40fa --- /dev/null +++ b/lib/Exceptions/FederatedSyncRequestException.php @@ -0,0 +1,54 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Exceptions; + +use OCP\AppFramework\Http; +use Throwable; + +class FederatedSyncRequestException extends FederatedSyncException { + public const STATUS = Http::STATUS_NOT_FOUND; + + /** + * FederatedItemConflictException constructor. + * + * @param string $message + * @param int $code + * @param Throwable|null $previous + */ + public function __construct( + string $message = '', + int $code = 0, + ?Throwable $previous = null + ) { + parent::__construct($message, ($code > 0) ? $code : self::STATUS, $previous); + $this->setStatus(self::STATUS); + } +} diff --git a/lib/Exceptions/InternalAsyncException.php b/lib/Exceptions/InternalAsyncException.php new file mode 100644 index 000000000..2f12f0012 --- /dev/null +++ b/lib/Exceptions/InternalAsyncException.php @@ -0,0 +1,37 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Exceptions; + +use Exception; + +class InternalAsyncException extends Exception { +} diff --git a/lib/Exceptions/SyncedItemLockException.php b/lib/Exceptions/SyncedItemLockException.php new file mode 100644 index 000000000..bd7262985 --- /dev/null +++ b/lib/Exceptions/SyncedItemLockException.php @@ -0,0 +1,47 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Circles\Exceptions; + +use OCP\AppFramework\Http; +use Throwable; + +class SyncedItemLockException extends FederatedSyncException { + public const STATUS = Http::STATUS_LOCKED; + + public function __construct( + string $message = '', + int $code = 0, + ?Throwable $previous = null + ) { + parent::__construct($message, ($code > 0) ? $code : self::STATUS, $previous); + $this->setStatus(self::STATUS); + } +} diff --git a/lib/Exceptions/SyncedItemNotFoundException.php b/lib/Exceptions/SyncedItemNotFoundException.php index 537fd309b..280d77ea4 100644 --- a/lib/Exceptions/SyncedItemNotFoundException.php +++ b/lib/Exceptions/SyncedItemNotFoundException.php @@ -30,5 +30,18 @@ namespace OCA\Circles\Exceptions; -class SyncedItemNotFoundException extends FederatedItemNotFoundException { +use OCP\AppFramework\Http; +use Throwable; + +class SyncedItemNotFoundException extends FederatedSyncException { + public const STATUS = Http::STATUS_NOT_FOUND; + + public function __construct( + string $message = '', + int $code = 0, + ?Throwable $previous = null + ) { + parent::__construct($message, ($code > 0) ? $code : self::STATUS, $previous); + $this->setStatus(self::STATUS); + } } diff --git a/lib/Exceptions/SyncedShareNotFoundException.php b/lib/Exceptions/SyncedShareNotFoundException.php index 10f27377d..1d45233f4 100644 --- a/lib/Exceptions/SyncedShareNotFoundException.php +++ b/lib/Exceptions/SyncedShareNotFoundException.php @@ -30,5 +30,18 @@ namespace OCA\Circles\Exceptions; +use OCP\AppFramework\Http; +use Throwable; + class SyncedShareNotFoundException extends FederatedItemNotFoundException { + public const STATUS = Http::STATUS_NOT_FOUND; + + public function __construct( + string $message = '', + int $code = 0, + ?Throwable $previous = null + ) { + parent::__construct($message, ($code > 0) ? $code : self::STATUS, $previous); + $this->setStatus(self::STATUS); + } } diff --git a/lib/Exceptions/SyncedSharedAlreadyExistException.php b/lib/Exceptions/SyncedSharedAlreadyExistException.php index 747f8c58f..a8ead52bf 100644 --- a/lib/Exceptions/SyncedSharedAlreadyExistException.php +++ b/lib/Exceptions/SyncedSharedAlreadyExistException.php @@ -30,7 +30,18 @@ namespace OCA\Circles\Exceptions; -use Exception; +use OCP\AppFramework\Http; +use Throwable; -class SyncedSharedAlreadyExistException extends Exception { +class SyncedSharedAlreadyExistException extends FederatedSyncException { + public const STATUS = Http::STATUS_BAD_REQUEST; + + public function __construct( + string $message = '', + int $code = 0, + ?Throwable $previous = null + ) { + parent::__construct($message, ($code > 0) ? $code : self::STATUS, $previous); + $this->setStatus(self::STATUS); + } } diff --git a/lib/ICircleSharesManager.php b/lib/ICircleSharesManager.php index 2785343a9..97ce19cfb 100644 --- a/lib/ICircleSharesManager.php +++ b/lib/ICircleSharesManager.php @@ -90,7 +90,13 @@ public function deleteShare(string $itemId, string $circleId): void; * @param string $itemId * @param array $extraData */ - public function updateItem(string $itemId, array $extraData): void; + public function updateItem( + string $itemId, + string $updateType, + string $updateTypeId, + array $extraData, + bool $sumCheck + ): void; /** * Initiate the deletion of an Item diff --git a/lib/IFederatedSyncManager.php b/lib/IFederatedSyncManager.php index cd268771c..725421b97 100644 --- a/lib/IFederatedSyncManager.php +++ b/lib/IFederatedSyncManager.php @@ -31,7 +31,6 @@ namespace OCA\Circles; -use JsonSerializable; use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\Model\FederatedUser; @@ -282,15 +281,39 @@ public function onShareDeletion( * Method is only called on the instance that owns the shared item * * @param string $itemId + * @param string $updateType + * @param string $updateTypeId * @param array $extraData * @param FederatedUser $federatedUser * - * @return array + * @return bool + * // TODO: define Exception that can be thrown by app: + * // - itemnotfound + * // - ItemUpdateException */ - public function isItemUpdatable( + public function isItemModifiable( string $itemId, + string $updateType, + string $updateTypeId, array $extraData, IFederatedUser $federatedUser - ): array; + ): bool; + + + /** + * @param string $itemId + * @param string $updateType + * @param string $updateTypeId + * @param array $extraData + * @param FederatedUser $federatedUser + */ + public function onItemModification( + string $itemId, + string $updateType, + string $updateTypeId, + array $extraData, + IFederatedUser $federatedUser + ): void; + } diff --git a/lib/IInternalAsync.php b/lib/IInternalAsync.php new file mode 100644 index 000000000..51c70aba2 --- /dev/null +++ b/lib/IInternalAsync.php @@ -0,0 +1,42 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles; + +use OCA\Circles\Tools\Model\ReferencedDataStore; + +interface IInternalAsync { + + public const STORE_INTERNAL_ASYNC = '_internalAsync'; + + public function runAsynced(ReferencedDataStore $store): void; + +} diff --git a/lib/InternalAsync/AsyncItemUpdate.php b/lib/InternalAsync/AsyncItemUpdate.php new file mode 100644 index 000000000..a890598d1 --- /dev/null +++ b/lib/InternalAsync/AsyncItemUpdate.php @@ -0,0 +1,187 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\InternalAsync; + +use OCA\Circles\Db\CircleRequest; +use OCA\Circles\Db\SyncedItemLockRequest; +use OCA\Circles\Db\SyncedItemRequest; +use OCA\Circles\Db\SyncedShareRequest; +use OCA\Circles\Exceptions\FederatedEventException; +use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; +use OCA\Circles\Exceptions\InitiatorNotConfirmedException; +use OCA\Circles\Exceptions\OwnerNotFoundException; +use OCA\Circles\Exceptions\RemoteInstanceException; +use OCA\Circles\Exceptions\RemoteNotFoundException; +use OCA\Circles\Exceptions\RemoteResourceNotFoundException; +use OCA\Circles\Exceptions\RequestBuilderException; +use OCA\Circles\Exceptions\SyncedItemNotFoundException; +use OCA\Circles\Exceptions\UnknownRemoteException; +use OCA\Circles\FederatedItems\FederatedSync\ItemUpdate; +use OCA\Circles\IInternalAsync; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\SyncedItem; +use OCA\Circles\Model\SyncedItemLock; +use OCA\Circles\Model\SyncedShare; +use OCA\Circles\Service\DebugService; +use OCA\Circles\Service\FederatedEventService; +use OCA\Circles\Service\FederatedSyncService; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Model\ReferencedDataStore; + + +class AsyncItemUpdate implements IInternalAsync { + + private CircleRequest $circleRequest; + private SyncedItemRequest $syncedItemRequest; + private SyncedShareRequest $syncedShareRequest; + private SyncedItemLockRequest $syncedItemLockRequest; + private FederatedEventService $federatedEventService; + private FederatedSyncService $federatedSyncService; + private DebugService $debugService; + + public function __construct( + CircleRequest $circleRequest, + SyncedItemRequest $syncedItemRequest, + SyncedShareRequest $syncedShareRequest, + SyncedItemLockRequest $syncedItemLockRequest, + FederatedEventService $federatedEventService, + FederatedSyncService $federatedSyncService, + DebugService $debugService + ) { + $this->circleRequest = $circleRequest; + $this->syncedItemRequest = $syncedItemRequest; + $this->syncedShareRequest = $syncedShareRequest; + $this->syncedItemLockRequest = $syncedItemLockRequest; + $this->federatedEventService = $federatedEventService; + $this->federatedSyncService = $federatedSyncService; + $this->debugService = $debugService; + } + + + /** + * @param ReferencedDataStore $store + * + * @throws FederatedSyncManagerNotFoundException + * @throws SyncedItemNotFoundException + * @throws InvalidItemException + */ + public function runAsynced(ReferencedDataStore $store): void { + /** @var SyncedItem $syncedItem */ + $syncedItem = $store->gObj('syncedItem'); + /** @var SyncedItemLock $syncedLock */ + $syncedLock = $store->gObj('syncedItemLock'); + + $item = $this->federatedSyncService->initSyncManager($syncedItem) + ->serializeItem($syncedItem->getItemId()); + $syncedItem->setSerialized($item); + + $this->updateChecksum($syncedItem); + $this->broadcastItemUpdate($syncedItem); + + $this->removeLock($syncedLock); + } + + + /** + * @param Circle $circle + * @param SyncedItem $syncedItem + * + * @throws FederatedEventException + * @throws FederatedItemException + * @throws InitiatorNotConfirmedException + * @throws OwnerNotFoundException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException + */ + private function broadcastItemUpdate(SyncedItem $item): void { + $item->setSerialized(); + + foreach ($this->getAffectedCircles($item->getSingleId()) as $circle) { + $event = new FederatedEvent(ItemUpdate::class); + $event->setCircle($circle) + ->setSyncedItem($item); + + $this->debugService->info( + 'generating {`IFederatedEvent} using {event.class}', + $circle->getSingleId(), + [ + 'event' => $event, + 'syncedItem' => $item, + 'circle' => $circle + ] + ); + + // TODO: confirm there is no re-async as we are already on a // thread (even with multiple circles) + $this->federatedEventService->newEvent($event); + } + } + + + /** + * @param string $singleId + * + * @return Circle[] + * @throws RequestBuilderException + */ + private function getAffectedCircles(string $singleId): array { + $circleIds = array_map( + function (SyncedShare $share): string { + return $share->getCircleId(); + }, $this->syncedShareRequest->getshares($singleId) + ); + + return $this->circleRequest->getCirclesByIds($circleIds); + } + + + /** + * @param SyncedItem $syncedItem + */ + private function updateChecksum(SyncedItem $syncedItem): void { + $sum = md5(json_encode($syncedItem->getSerialized())); + + $this->syncedItemRequest->updateChecksum($syncedItem->getSingleId(), $sum); + } + + + /** + * @param SyncedItemLock $syncedLock + */ + private function removeLock(SyncedItemLock $syncedLock): void { + $this->syncedItemLockRequest->remove($syncedLock); + } +} diff --git a/lib/InternalAsync/AsyncTest.php b/lib/InternalAsync/AsyncTest.php new file mode 100644 index 000000000..2c577bca8 --- /dev/null +++ b/lib/InternalAsync/AsyncTest.php @@ -0,0 +1,63 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\InternalAsync; + +use OCA\Circles\IInternalAsync; +use OCA\Circles\Service\AsyncService; +use OCA\Circles\Tools\Model\ReferencedDataStore; + + +class AsyncTest implements IInternalAsync { + + + private AsyncService $asyncService; + + public function __construct(AsyncService $asyncService) { + $this->asyncService = $asyncService; + } + + + public function runAsynced(ReferencedDataStore $store): void { + + \OC::$server->getLogger()->log(3, '-runAsynced ' . json_encode($store)); + $this->asyncService->asyncInternal( + AsyncTest::class, + new ReferencedDataStore( + [ + 'action' => 'test', + 'federatedUser' => $store->gObj('federatedUser') + ] + ) + ); + } + +} diff --git a/lib/Migration/Version0025Date20220510104622.php b/lib/Migration/Version0025Date20220510104622.php index f68192939..9cb7db5cf 100644 --- a/lib/Migration/Version0025Date20220510104622.php +++ b/lib/Migration/Version0025Date20220510104622.php @@ -61,6 +61,28 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt /** @var ISchemaWrapper $schema */ $schema = $schemaClosure(); + if ($schema->hasTable('circles_event')) { + $table = $schema->getTable('circles_event'); + if (!$table->hasColumn('event_type')) { + $table->addColumn( + 'event_type', Types::STRING, [ + 'notnull' => false, + 'default' => 'broadcast', + 'length' => 15 + ] + ); + $table->addIndex(['event_type']); + } + if (!$table->hasColumn('store')) { + $table->addColumn( + 'store', Types::TEXT, [ + 'notnull' => false, + 'default' => '' + ] + ); + } + } + if (!$schema->hasTable('circles_item')) { $table = $schema->createTable('circles_item'); $table->addColumn( @@ -156,12 +178,12 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt 'unsigned' => true, ] ); - $table->addColumn( - 'single_id', Types::STRING, [ - 'notnull' => false, - 'length' => 31, - ] - ); +// $table->addColumn( +// 'single_id', Types::STRING, [ +// 'notnull' => false, +// 'length' => 31, +// ] +// ); $table->addColumn( 'update_type', Types::STRING, [ 'notnull' => false, @@ -183,7 +205,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt ); $table->setPrimaryKey(['id']); - $table->addUniqueIndex(['single_id', 'update_type', 'update_type_id'], 'c_siututi'); + $table->addUniqueIndex(['update_type', 'update_type_id'], 'c_ututi'); } if (!$schema->hasTable('circles_debug')) { diff --git a/lib/Model/Federated/EventWrapper.php b/lib/Model/Federated/EventWrapper.php index 7338941df..267aac678 100644 --- a/lib/Model/Federated/EventWrapper.php +++ b/lib/Model/Federated/EventWrapper.php @@ -31,11 +31,12 @@ namespace OCA\Circles\Model\Federated; +use JsonSerializable; use OCA\Circles\Tools\Db\IQueryRow; use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Model\ReferencedDataStore; use OCA\Circles\Tools\Model\SimpleDataStore; use OCA\Circles\Tools\Traits\TArrayTools; -use JsonSerializable; /** * Class EventWrapper @@ -51,6 +52,9 @@ class EventWrapper implements IQueryRow, JsonSerializable { public const STATUS_DONE = 8; public const STATUS_OVER = 9; + public const TYPE_BROADCAST = 'broadcast'; + public const TYPE_INTERNAL = 'internal'; + /** @var string */ private $token = ''; @@ -58,6 +62,9 @@ class EventWrapper implements IQueryRow, JsonSerializable { /** @var FederatedEvent */ private $event; + private string $eventType; + private ?ReferencedDataStore $store = null; + /** @var SimpleDataStore */ private $result; @@ -80,7 +87,8 @@ class EventWrapper implements IQueryRow, JsonSerializable { private $creation; - public function __construct() { + public function __construct(string $eventType = '') { + $this->eventType = $eventType; $this->result = new SimpleDataStore(); } @@ -130,6 +138,51 @@ public function hasEvent(): bool { } + /** + * @return ReferencedDataStore + */ + public function getStore(): ReferencedDataStore { + return $this->store; + } + + /** + * @param ReferencedDataStore $store + * + * @return self + */ + public function setStore(ReferencedDataStore $store): self { + $this->store = $store; + + return $this; + } + + /** + * @return bool + */ + public function hasStore(): bool { + return ($this->store !== null); + } + + + /** + * @param string $eventType + * + * @return EventWrapper + */ + public function setEventType(string $eventType): self { + $this->eventType = $eventType; + + return $this; + } + + /** + * @return string + */ + public function getEventType(): string { + return $this->eventType; + } + + /** * @param SimpleDataStore $result * @@ -262,6 +315,45 @@ public function setCreation(int $creation): self { } + /** + * @param array $data + * + * @return IQueryRow + * @throws InvalidItemException + */ + public function importFromDatabase(array $data): IQueryRow { + $this->setToken($this->get('token', $data)); + $this->setInstance($this->get('instance', $data)); + $this->setEventType($this->get('event_type', $data)); + $this->setInterface($this->getInt('interface', $data)); + $this->setSeverity($this->getInt('severity', $data, FederatedEvent::SEVERITY_LOW)); + $this->setStatus($this->getInt('status', $data, self::STATUS_INIT)); + + if ($this->getEventType() === self::TYPE_BROADCAST) { + $event = new FederatedEvent(); + $event->import($this->getArray('event', $data)); + $this->setEvent($event); + } + + if ($this->getEventType() === self::TYPE_INTERNAL) { + $store = new ReferencedDataStore(); + $store->import($this->getArray('store', $data)); + $this->setStore($store); + } + +// try { +// $store = new ReferencedDataStore(); +// $store->import($this->getArray('store', $data)); +// $this->setStore($store); +// } catch (InvalidItemException $e) { +// } + + $this->setResult(new SimpleDataStore($this->getArray('result', $data))); + + return $this; + } + + /** * @param array $data * @@ -271,13 +363,22 @@ public function setCreation(int $creation): self { public function import(array $data): self { $this->setToken($this->get('token', $data)); $this->setInstance($this->get('instance', $data)); + $this->setEventType($this->get('eventType', $data)); $this->setInterface($this->getInt('interface', $data)); $this->setSeverity($this->getInt('severity', $data, FederatedEvent::SEVERITY_LOW)); $this->setStatus($this->getInt('status', $data, self::STATUS_INIT)); - $event = new FederatedEvent(); - $event->import($this->getArray('event', $data)); - $this->setEvent($event); + if ($this->getEventType() === self::TYPE_BROADCAST) { + $event = new FederatedEvent(); + $event->import($this->getArray('event', $data)); + $this->setEvent($event); + } + + if ($this->getEventType() === self::TYPE_INTERNAL) { + $store = new ReferencedDataStore(); + $store->import($this->getArray('store', $data)); + $this->setStore($store); + } $this->setResult(new SimpleDataStore($this->getArray('result', $data))); $this->setCreation($this->getInt('creation', $data)); @@ -293,35 +394,14 @@ public function jsonSerialize(): array { return [ 'token' => $this->getToken(), 'instance' => $this->getInstance(), + 'eventType' => $this->getEventType(), 'interface' => $this->getInterface(), - 'event' => $this->getEvent(), + 'event' => ($this->hasEvent()) ? $this->getEvent() : null, + 'store' => ($this->hasStore()) ? $this->getStore() : null, 'result' => $this->getResult(), 'severity' => $this->getSeverity(), 'status' => $this->getStatus() // 'creation' => $this->getCreation() ]; } - - - /** - * @param array $data - * - * @return IQueryRow - * @throws InvalidItemException - */ - public function importFromDatabase(array $data): IQueryRow { - $this->setToken($this->get('token', $data)); - $this->setInstance($this->get('instance', $data)); - $this->setInterface($this->getInt('interface', $data)); - $this->setSeverity($this->getInt('severity', $data, FederatedEvent::SEVERITY_LOW)); - $this->setStatus($this->getInt('status', $data, self::STATUS_INIT)); - - $event = new FederatedEvent(); - $event->import($this->getArray('event', $data)); - $this->setEvent($event); - - $this->setResult(new SimpleDataStore($this->getArray('result', $data))); - - return $this; - } } diff --git a/lib/Model/FederatedUser.php b/lib/Model/FederatedUser.php index ac6a7ca2e..bfcf25e29 100644 --- a/lib/Model/FederatedUser.php +++ b/lib/Model/FederatedUser.php @@ -31,19 +31,19 @@ namespace OCA\Circles\Model; -use OCA\Circles\Tools\Db\IQueryRow; -use OCA\Circles\Tools\Exceptions\InvalidItemException; -use OCA\Circles\Tools\IDeserializable; -use OCA\Circles\Tools\Traits\TDeserialize; -use OCA\Circles\Tools\Traits\TArrayTools; use JsonSerializable; use OCA\Circles\Exceptions\FederatedUserNotFoundException; use OCA\Circles\Exceptions\MembershipNotFoundException; use OCA\Circles\Exceptions\OwnerNotFoundException; use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\UnknownInterfaceException; -use OCA\Circles\IFederatedUser; use OCA\Circles\IEntity; +use OCA\Circles\IFederatedUser; +use OCA\Circles\Tools\Db\IQueryRow; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\Traits\TArrayTools; +use OCA\Circles\Tools\Traits\TDeserialize; /** * Class FederatedUser diff --git a/lib/Model/SyncedItemLock.php b/lib/Model/SyncedItemLock.php index 47f8ff045..5ace71e68 100644 --- a/lib/Model/SyncedItemLock.php +++ b/lib/Model/SyncedItemLock.php @@ -36,16 +36,17 @@ use OCA\Circles\Tools\Db\IQueryRow; use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\IDeserializable; +use OCA\Circles\Tools\IReferencedObject; use OCA\Circles\Tools\Traits\TArrayTools; -class SyncedItemLock implements IDeserializable, IQueryRow, JsonSerializable { +class SyncedItemLock implements IReferencedObject, IQueryRow, JsonSerializable { use TArrayTools; private int $id; - private string $singleId; +// private string $singleId; private string $updateType; private string $updateTypeId; - private int $time; + private int $time = 0; private bool $verifyChecksum; @@ -79,23 +80,23 @@ public function getId(): int { } - /** - * @param string $singleId - * - * @return SyncedItemLock - */ - public function setSingleId(string $singleId): self { - $this->singleId = $singleId; - - return $this; - } - - /** - * @return string - */ - public function getSingleId(): string { - return $this->singleId; - } +// /** +// * @param string $singleId +// * +// * @return SyncedItemLock +// */ +// public function setSingleId(string $singleId): self { +// $this->singleId = $singleId; +// +// return $this; +// } +// +// /** +// * @return string +// */ +// public function getSingleId(): string { +// return $this->singleId; +// } /** * @param string $updateType @@ -180,11 +181,11 @@ public function isVerifyChecksum(): bool { * @throws InvalidItemException */ public function import(array $data): IDeserializable { - if ($this->getInt('singleId', $data) === 0) { - throw new InvalidItemException(); - } +// if ($this->getInt('singleId', $data) === 0) { +// throw new InvalidItemException(); +// } - $this->setSingleId($this->get('singleId', $data)); +// $this->setSingleId($this->get('singleId', $data)); $this->setUpdateType($this->get('updateType', $data)); $this->setUpdateTypeId($this->get('updateTypeId', $data)); $this->setTime($this->getInt('time', $data)); @@ -205,7 +206,6 @@ public function importFromDatabase(array $data, string $prefix = ''): IQueryRow throw new ShareTokenNotFoundException(); } - $this->setSingleId($this->get($prefix . 'single_id', $data)); $this->setUpdateType($this->get($prefix . 'update_type', $data)); $this->setUpdateTypeId($this->get($prefix . 'update_type_id', $data)); $this->setTime($this->getInt($prefix . 'time', $data)); @@ -218,7 +218,6 @@ public function importFromDatabase(array $data, string $prefix = ''): IQueryRow */ public function jsonSerialize(): array { return [ - 'singleId' => $this->getSingleId(), 'updateType' => $this->getUpdateType(), 'updateTypeId' => $this->getUpdateTypeId(), 'time' => $this->getTime(), diff --git a/lib/Model/SyncedWrapper.php b/lib/Model/SyncedWrapper.php index e4d4081a5..316f05171 100644 --- a/lib/Model/SyncedWrapper.php +++ b/lib/Model/SyncedWrapper.php @@ -45,18 +45,21 @@ class SyncedWrapper implements IReferencedObject, JsonSerializable { private ?IFederatedUser $federatedUser; private ?SyncedItem $item; + private ?SyncedItemLock $lock; private ?SyncedShare $share; private array $extraData; public function __construct( ?IFederatedUser $federatedUser = null, ?SyncedItem $item = null, + ?SyncedItemLock $lock = null, ?SyncedShare $share = null, array $extraData = [] ) { $this->federatedUser = $federatedUser; $this->item = $item; $this->share = $share; + $this->lock = $lock; $this->extraData = $extraData; } @@ -113,6 +116,32 @@ public function getItem(): ?SyncedItem { } + /** + * @param SyncedItem $lock + * + * @return SyncedWrapper + */ + public function setLock(SyncedItemLock $lock): self { + $this->lock = $lock; + + return $this; + } + + /** + * @return bool + */ + public function hasLock(): bool { + return !is_null($this->lock); + } + + /** + * @return SyncedItemLock + */ + public function getLock(): ?SyncedItemLock { + return $this->lock; + } + + /** * @param SyncedShare $share * @@ -179,6 +208,13 @@ public function import(array $data): IDeserializable { } catch (InvalidItemException $e) { } + try { + /** @var SyncedItemLock $lock */ + $lock = $this->deserialize($this->getArray('lock', $data), SyncedItemLock::class); + $this->setLock($lock); + } catch (InvalidItemException $e) { + } + try { /** @var SyncedShare $share */ $share = $this->deserialize($this->getArray('share', $data), SyncedShare::class); @@ -200,6 +236,7 @@ public function jsonSerialize(): array { 'federatedUser' => $this->getFederatedUser(), 'item' => $this->getItem(), 'share' => $this->getShare(), + 'lock' => $this->getLock(), 'extraData' => $this->getExtraData() ]; } diff --git a/lib/Service/AsyncService.php b/lib/Service/AsyncService.php new file mode 100644 index 000000000..2cd8d762b --- /dev/null +++ b/lib/Service/AsyncService.php @@ -0,0 +1,258 @@ + + * @copyright 2022 + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCA\Circles\Service; + +use OC; +use OCA\Circles\Db\EventWrapperRequest; +use OCA\Circles\Exceptions\InternalAsyncException; +use OCA\Circles\IInternalAsync; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Federated\EventWrapper; +use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Exceptions\RequestNetworkException; +use OCA\Circles\Tools\Model\NCRequest; +use OCA\Circles\Tools\Model\ReferencedDataStore; +use OCA\Circles\Tools\Model\Request; +use OCA\Circles\Tools\Traits\TAsync; +use OCA\Circles\Tools\Traits\TNCRequest; +use OCA\Circles\Tools\Traits\TStringTools; +use ReflectionClass; +use ReflectionException; + +class AsyncService { + use TAsync; + use TStringTools; + use TNCRequest; + + private EventWrapperRequest $eventWrapperRequest; + private ConfigService $configService; + + private bool $asynced = false; + private bool $splittable = false; + + public function __construct( + EventWrapperRequest $eventWrapperRequest, + ConfigService $configService + ) { + $this->eventWrapperRequest = $eventWrapperRequest; + $this->configService = $configService; + } + + + /** + * split the process, anything after calling this method is out of main process. + * Will only work if isSplittable() is true. + */ + public function split(string $reason = ''): void { + if (!$this->isSplittable()) { + return; + } + + $this->async($reason); + $this->setAsynced(); + } + + public function splitArray(array $array): void { + $this->split(json_encode($array)); + } + + + public function isSplittable(): bool { + return $this->splittable; + } + + public function setSplittable(bool $splittable): void { + $this->splittable = $splittable; + } + + /** + * call this method only from WrappedEventController to confirm further process that + * we are already not running on a main process. + * + * @param bool $asynced + */ + public function setAsynced(bool $asynced = true): void { + $this->asynced = $asynced; + } + + public function isAsynced(): bool { + return $this->asynced; + } + + + /** + * @throws RequestNetworkException + */ + public function asyncBroadcast(FederatedEvent $event, array $instances) { + if (empty($instances) && !$event->isAsync()) { + return; + } + + $wrapper = new EventWrapper(EventWrapper::TYPE_BROADCAST); + $wrapper->setEvent($event); + $wrapper->setToken($this->uuid()); + $wrapper->setCreation(time()); + $wrapper->setSeverity($event->getSeverity()); + + if ($event->isAsync()) { + $wrapper->setInstance($this->configService->getLoopbackInstance()); + $this->eventWrapperRequest->save($wrapper); + } + + foreach ($instances as $instance) { + if ($event->getCircle()->isConfig(Circle::CFG_LOCAL)) { + break; + } + + $wrapper->setInstance($instance->getInstance()); + $wrapper->setInterface($instance->getInterface()); + // TODO: implement single save of multiple wrappers to avoid 10+ queries on big circles with + // a lot of instances + $this->eventWrapperRequest->save($wrapper); + } + + $event->setWrapperToken($wrapper->getToken()); + + if ($this->isAsynced()) { + // we're not on main process, we run the broadcast on this thread. + // Also cannot add EventWrapperService to DI or loop. + /** @var EventWrapperService $eventWrapperService */ + $eventWrapperService = \OC::$server->get(EventWrapperService::class); + $eventWrapperService->performBroadcast($wrapper->getToken()); + + return; + } + + try { + $request = new NCRequest('', Request::TYPE_POST); + $this->configService->configureLoopbackRequest( + $request, + 'circles.EventWrapper.asyncBroadcast', + ['token' => $wrapper->getToken()] + ); + + $this->doRequest($request); + } catch (RequestNetworkException $e) { + $this->e($e, ['wrapper' => $wrapper]); + } + } + + + /** + * @param string $internalAsync + * @param ReferencedDataStore|null $store + */ + public function asyncInternal(string $internalAsync, ?ReferencedDataStore $store = null): void { + if (is_null($store)) { + $store = new ReferencedDataStore(); + } + + $store->s(IInternalAsync::STORE_INTERNAL_ASYNC, $internalAsync); + + $wrapper = new EventWrapper(EventWrapper::TYPE_INTERNAL); + $wrapper->setStore($store); + $wrapper->setToken($this->uuid()); + $wrapper->setCreation(time()); + + $this->eventWrapperRequest->save($wrapper); + + if ($this->isAsynced()) { + // we're not on main process, we run it on this thread. + // Also cannot add EventWrapperService to DI or loop. + + /** @var EventWrapperService $eventWrapperService */ + $eventWrapperService = \OC::$server->get(EventWrapperService::class); + $eventWrapperService->performInternal($wrapper->getToken()); + + return; + } + + $request = new NCRequest('', Request::TYPE_POST); + $this->configService->configureLoopbackRequest( + $request, + 'circles.EventWrapper.asyncInternal', + ['token' => $wrapper->getToken()] + ); + + try { + $this->doRequest($request); + } catch (RequestNetworkException $e) { + $this->e($e, ['wrapper' => $wrapper]); + } + } + + + /** + * @param EventWrapper $wrapper + * + * @throws InternalAsyncException + * @throws InvalidItemException + */ + public function runInternalAsync(EventWrapper $wrapper): void { + $store = $wrapper->getStore(); + $internalAsync = $this->getInternalAsync($store); + + $store->u(IInternalAsync::STORE_INTERNAL_ASYNC); + $internalAsync->runAsynced($store); + } + + + /** + * @param ReferencedDataStore $store + * + * @return IInternalAsync + * @throws InvalidItemException + * @throws InternalAsyncException + */ + private function getInternalAsync(ReferencedDataStore $store): IInternalAsync { + $class = $store->g(IInternalAsync::STORE_INTERNAL_ASYNC); + + try { + $test = new ReflectionClass($class); + } catch (ReflectionException $e) { + throw new InternalAsyncException('ReflectionException with ' . $class . ': ' . $e->getMessage()); + } + + if (!in_array(IInternalAsync::class, $test->getInterfaceNames())) { + throw new InternalAsyncException($class . ' does not implements IInternalAsync'); + } + + $item = OC::$server->get($class); + if (!($item instanceof IInternalAsync)) { + throw new InternalAsyncException($class . ' not an IInternalAsync'); + } + + return $item; + } + +} diff --git a/lib/Service/EventWrapperService.php b/lib/Service/EventWrapperService.php index 07ad792d1..79e6ec4d4 100644 --- a/lib/Service/EventWrapperService.php +++ b/lib/Service/EventWrapperService.php @@ -32,6 +32,7 @@ use Exception; use OCA\Circles\Db\EventWrapperRequest; +use OCA\Circles\Exceptions\EventWrapperNotFoundException; use OCA\Circles\Model\Federated\EventWrapper; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Tools\ActivityPub\NCSignature; @@ -68,6 +69,8 @@ class EventWrapperService extends NCSignature { /** @var RemoteUpstreamService */ private $remoteUpstreamService; + private AsyncService $asyncService; + /** @var ConfigService */ private $configService; @@ -78,17 +81,20 @@ class EventWrapperService extends NCSignature { * @param EventWrapperRequest $eventWrapperRequest * @param FederatedEventService $federatedEventService * @param RemoteUpstreamService $remoteUpstreamService + * @param AsyncService $asyncService * @param ConfigService $configService */ public function __construct( EventWrapperRequest $eventWrapperRequest, FederatedEventService $federatedEventService, RemoteUpstreamService $remoteUpstreamService, + AsyncService $asyncService, ConfigService $configService ) { $this->eventWrapperRequest = $eventWrapperRequest; $this->federatedEventService = $federatedEventService; $this->remoteUpstreamService = $remoteUpstreamService; + $this->asyncService = $asyncService; $this->configService = $configService; } @@ -98,7 +104,7 @@ public function __construct( * @param bool $refresh */ public function confirmStatus(string $token, bool $refresh = false): void { - $wrappers = $this->eventWrapperRequest->getByToken($token); + $wrappers = $this->eventWrapperRequest->getBroadcastByToken($token); foreach ($wrappers as $wrapper) { $status = $wrapper->getStatus(); @@ -181,4 +187,56 @@ function (EventWrapper $event): string { return array_values(array_unique($token)); } + + + /** + * @param string $token + * + * @return EventWrapper[] + */ + public function getBroadcastByToken(string $token): array { + return $this->eventWrapperRequest->getBroadcastByToken($token); + } + + /** + * @param string $token + * + * @return EventWrapper + * @throws EventWrapperNotFoundException + */ + public function getInternalEventByToken(string $token): EventWrapper { + return $this->eventWrapperRequest->getInternalByToken($token); + } + + + /** + * @param string $token + */ + public function performInternal(string $token): void { + try { + $wrapper = $this->getInternalEventByToken($token); + $this->asyncService->runInternalAsync($wrapper); + } catch (EventWrapperNotFoundException $e) { + } + + // TODO: delete token in table. + } + + + /** + * @param string $token + * @param array|null $wrappers + */ + public function performBroadcast(string $token, ?array $wrappers = null): void { + if (is_null($wrappers)) { + $wrappers = $this->getBroadcastByToken($token); + } + + foreach ($wrappers as $wrapper) { + $this->manageWrapper($wrapper); + } + + $this->confirmStatus($token); + } + } diff --git a/lib/Service/FederatedEventService.php b/lib/Service/FederatedEventService.php index a715a6a6e..1c7b762a3 100644 --- a/lib/Service/FederatedEventService.php +++ b/lib/Service/FederatedEventService.php @@ -65,8 +65,6 @@ use OCA\Circles\Model\Member; use OCA\Circles\Tools\ActivityPub\NCSignature; use OCA\Circles\Tools\Exceptions\RequestNetworkException; -use OCA\Circles\Tools\Model\NCRequest; -use OCA\Circles\Tools\Model\Request; use OCA\Circles\Tools\Traits\TNCRequest; use OCA\Circles\Tools\Traits\TStringTools; use ReflectionClass; @@ -97,6 +95,8 @@ class FederatedEventService extends NCSignature { /** @var InterfaceService */ private $interfaceService; + private AsyncService $asyncService; + /** @var ConfigService */ private $configService; @@ -111,6 +111,7 @@ class FederatedEventService extends NCSignature { * @param MemberRequest $memberRequest * @param RemoteUpstreamService $remoteUpstreamService * @param InterfaceService $interfaceService + * @param AsyncService $asyncService * @param ConfigService $configService * @param DebugService $debugService */ @@ -120,6 +121,7 @@ public function __construct( MemberRequest $memberRequest, RemoteUpstreamService $remoteUpstreamService, InterfaceService $interfaceService, + AsyncService $asyncService, ConfigService $configService, DebugService $debugService ) { @@ -128,6 +130,7 @@ public function __construct( $this->memberRequest = $memberRequest; $this->remoteUpstreamService = $remoteUpstreamService; $this->interfaceService = $interfaceService; + $this->asyncService = $asyncService; $this->configService = $configService; $this->debugService = $debugService; } @@ -388,46 +391,7 @@ private function configureEvent(FederatedEvent $event, IFederatedItem $item) { * @throws RequestBuilderException */ public function initBroadcast(FederatedEvent $event): void { - $instances = $this->getInstances($event); - if (empty($instances) && !$event->isAsync()) { - return; - } - - $wrapper = new EventWrapper(); - $wrapper->setEvent($event); - $wrapper->setToken($this->uuid()); - $wrapper->setCreation(time()); - $wrapper->setSeverity($event->getSeverity()); - - if ($event->isAsync()) { - $wrapper->setInstance($this->configService->getLoopbackInstance()); - $this->eventWrapperRequest->save($wrapper); - } - - foreach ($instances as $instance) { - if ($event->getCircle()->isConfig(Circle::CFG_LOCAL)) { - break; - } - - $wrapper->setInstance($instance->getInstance()); - $wrapper->setInterface($instance->getInterface()); - $this->eventWrapperRequest->save($wrapper); - } - - $request = new NCRequest('', Request::TYPE_POST); - $this->configService->configureLoopbackRequest( - $request, - 'circles.EventWrapper.asyncBroadcast', - ['token' => $wrapper->getToken()] - ); - - $event->setWrapperToken($wrapper->getToken()); - - try { - $this->doRequest($request); - } catch (RequestNetworkException $e) { - $this->e($e, ['wrapper' => $wrapper]); - } + $this->asyncService->asyncBroadcast($event, $this->getInstances($event)); } @@ -488,7 +452,7 @@ function (RemoteInstance $instance): string { * @param string $token */ public function manageResults(string $token): void { - $wrappers = $this->eventWrapperRequest->getByToken($token); + $wrappers = $this->eventWrapperRequest->getBroadcastByToken($token); $event = null; $results = []; diff --git a/lib/Service/FederatedSyncItemService.php b/lib/Service/FederatedSyncItemService.php index f10f52d37..9fc677f04 100644 --- a/lib/Service/FederatedSyncItemService.php +++ b/lib/Service/FederatedSyncItemService.php @@ -33,12 +33,15 @@ use Exception; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\RemoteRequest; +use OCA\Circles\Db\SyncedItemLockRequest; use OCA\Circles\Db\SyncedItemRequest; use OCA\Circles\Db\SyncedShareRequest; use OCA\Circles\Exceptions\FederatedEventException; use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Exceptions\FederatedSyncConflictException; use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; +use OCA\Circles\Exceptions\FederatedSyncPermissionException; +use OCA\Circles\Exceptions\FederatedSyncRequestException; use OCA\Circles\Exceptions\InitiatorNotConfirmedException; use OCA\Circles\Exceptions\InvalidIdException; use OCA\Circles\Exceptions\OwnerNotFoundException; @@ -46,67 +49,67 @@ use OCA\Circles\Exceptions\RemoteNotFoundException; use OCA\Circles\Exceptions\RemoteResourceNotFoundException; use OCA\Circles\Exceptions\RequestBuilderException; +use OCA\Circles\Exceptions\SyncedItemLockException; use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\Exceptions\UnknownRemoteException; -use OCA\Circles\FederatedItems\FederatedSync\ItemUpdate; use OCA\Circles\IFederatedUser; -use OCA\Circles\Model\Circle; -use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\InternalAsync\AsyncItemUpdate; use OCA\Circles\Model\Federated\RemoteInstance; use OCA\Circles\Model\SyncedItem; -use OCA\Circles\Model\SyncedShare; +use OCA\Circles\Model\SyncedItemLock; use OCA\Circles\Model\SyncedWrapper; use OCA\Circles\Tools\ActivityPub\NCSignature; use OCA\Circles\Tools\Exceptions\InvalidItemException; +use OCA\Circles\Tools\Model\ReferencedDataStore; use OCA\Circles\Tools\Model\Request; -use OCA\Circles\Tools\Model\SimpleDataStore; +use OCA\Circles\Tools\Traits\TAsync; use OCA\Circles\Tools\Traits\TDeserialize; use OCA\Circles\Tools\Traits\TStringTools; class FederatedSyncItemService extends NCSignature { use TStringTools; use TDeserialize; + use TAsync; + + const LOCK_RETRY_LIMIT = 3; + const LOCK_TIMEOUT = 15; // in seconds private SyncedItemRequest $syncedItemRequest; private SyncedShareRequest $syncedShareRequest; + private SyncedItemLockRequest $syncedItemLockRequest; private CircleRequest $circleRequest; private RemoteRequest $remoteRequest; private FederatedSyncService $federatedSyncService; private FederatedEventService $federatedEventService; private RemoteStreamService $remoteStreamService; private InterfaceService $interfaceService; + private AsyncService $asyncService; private DebugService $debugService; - /** - * @param SyncedItemRequest $syncedItemRequest - * @param SyncedShareRequest $syncedShareRequest - * @param RemoteRequest $remoteRequest - * @param FederatedSyncService $federatedSyncService - * @param FederatedEventService $federatedEventService - * @param RemoteStreamService $remoteStreamService - * @param InterfaceService $interfaceService - * @param DebugService $debugService - */ public function __construct( SyncedItemRequest $syncedItemRequest, SyncedShareRequest $syncedShareRequest, + SyncedItemLockRequest $syncedItemLockRequest, CircleRequest $circleRequest, RemoteRequest $remoteRequest, FederatedSyncService $federatedSyncService, FederatedEventService $federatedEventService, RemoteStreamService $remoteStreamService, InterfaceService $interfaceService, + AsyncService $asyncService, DebugService $debugService ) { $this->syncedItemRequest = $syncedItemRequest; $this->syncedShareRequest = $syncedShareRequest; + $this->syncedItemLockRequest = $syncedItemLockRequest; $this->circleRequest = $circleRequest; $this->remoteRequest = $remoteRequest; $this->federatedSyncService = $federatedSyncService; $this->federatedEventService = $federatedEventService; $this->remoteStreamService = $remoteStreamService; $this->interfaceService = $interfaceService; + $this->asyncService = $asyncService; $this->debugService = $debugService; } @@ -270,25 +273,61 @@ public function initSyncedItem( } + /** + * @param IFederatedUser $federatedUser + * @param SyncedItem $syncedItem + * @param SyncedItemLock $syncedLock + * @param array $extraData + * @param bool $initiatedRemotely + * + * @return array + * @throws FederatedEventException + * @throws FederatedItemException + * @throws FederatedSyncConflictException + * @throws FederatedSyncManagerNotFoundException + * @throws InitiatorNotConfirmedException + * @throws OwnerNotFoundException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException + * @throws UnknownRemoteException + */ public function requestSyncedItemUpdate( IFederatedUser $federatedUser, SyncedItem $syncedItem, - array $extraData = [] - ): array { + SyncedItemLock $syncedLock, + array $extraData = [], + ?string $remoteSum = null + ): void { // confirm item is local if ($syncedItem->isLocal()) { - return $this->requestSyncedItemUpdateLocal($federatedUser, $syncedItem, $extraData); - } else { - return $this->requestSyncedItemUpdateRemote($federatedUser, $syncedItem, $extraData); + $this->requestSyncedItemUpdateLocal( + $federatedUser, + $syncedItem, + $syncedLock, + $extraData, + $remoteSum + ); + + return; + } else if (is_null($remoteSum)) { + $this->requestSyncedItemUpdateRemote($federatedUser, $syncedItem, $syncedLock, $extraData); + + return; } + + throw new FederatedSyncConflictException(); } + /** * @param IFederatedUser $federatedUser * @param SyncedItem $syncedItem + * @param SyncedItemLock $syncedLock * @param array $extraData * - * @return SyncedItem + * @return array * @throws FederatedEventException * @throws FederatedItemException * @throws FederatedSyncManagerNotFoundException @@ -299,58 +338,59 @@ public function requestSyncedItemUpdate( * @throws RemoteResourceNotFoundException * @throws RequestBuilderException * @throws UnknownRemoteException + * @throws FederatedSyncPermissionException */ private function requestSyncedItemUpdateLocal( IFederatedUser $federatedUser, SyncedItem $syncedItem, - array $extraData = [] - ): array { - $item = $this->isItemUpdatable($federatedUser, $syncedItem, $extraData); + SyncedItemLock $syncedLock, + array $extraData = [], + ?string $remoteSum = null + ): void { + // item will be lock during the process, only to be unlocked when new item checksum have + // been calculated (on async process) + $this->manageLock($syncedItem, $syncedLock, $remoteSum); + + if (!$this->isItemModifiable($federatedUser, $syncedItem, $syncedLock, $extraData)) { + throw new FederatedSyncPermissionException('item modification not allowed'); + } $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); - $syncManager->syncItem( +// $syncManager->syncItem( +// $syncedItem->getItemId(), +// $item +// ); + + $syncManager->onItemModification( $syncedItem->getItemId(), - $item + $syncedLock->getUpdateType(), + $syncedLock->getUpdateTypeId(), + $extraData, + $federatedUser ); - $this->updateChecksum($syncedItem->getSingleId()); - - // broadcast update signal - // TODO: if request origin is not local, Async here, return $item to the remote instance - $this->broadcastItemUpdate($syncedItem->getSingleId()); - -// $syncedItem->setSerialized($item); - - return $item; - -// -// try { -// $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); -// } catch (SyncedItemNotFoundException $e) { -// $this->debugService->info( -// 'storing SyncedItem {syncedItem.singleId} in database', '', -// ['syncedItem' => $syncedItem] -// ); -// -// $this->syncedItemRequest->save($syncedItem); -// } -// -// $this->syncShareCreation($syncedItem, $circle, $extraData); -// $this->broadcastShareCreation($syncedItem, $circle, $extraData); -// -// $this->debugService->info( -// 'SyncedShare created and FederatedSync is on its way; {~end of main process}' -// ); + // this should split the process and give back hand if request is coming from a remote instance + $this->asyncService->splitArray(['success' => true]); + $this->asyncService->asyncInternal( + AsyncItemUpdate::class, + new ReferencedDataStore( + [ + 'syncedItem' => $syncedItem, + 'syncedItemLock' => $syncedLock, + ] + ) + ); } private function requestSyncedItemUpdateRemote( IFederatedUser $federatedUser, SyncedItem $syncedItem, + SyncedItemLock $syncedLock, array $extraData = [] ): array { - $wrapper = new SyncedWrapper($federatedUser, $syncedItem, null, $extraData); + $wrapper = new SyncedWrapper($federatedUser, $syncedItem, $syncedLock, null, $extraData); $this->interfaceService->setCurrentInterfaceFromInstance($syncedItem->getInstance()); $data = $this->remoteStreamService->resultRequestRemoteInstance( $syncedItem->getInstance(), @@ -359,87 +399,47 @@ private function requestSyncedItemUpdateRemote( $wrapper ); + if (!$this->getBool('success', $data)) { + throw new FederatedSyncRequestException(); + } + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); - $syncManager->syncItem( + $syncManager->onItemModification( $syncedItem->getItemId(), - $data + $syncedLock->getUpdateType(), + $syncedLock->getUpdateTypeId(), + $extraData, + $federatedUser ); - $this->updateChecksum($syncedItem->getSingleId(), $data); - - return $data; - } - - - private function updateChecksum(string $syncedItemId, ?array $data = null): void { - $currSum = ''; - if (is_null($data)) { - $knownItem = $this->getLocalSyncedItem($syncedItemId, true); - $data = $knownItem->getSerialized(); - $currSum = $knownItem->getChecksum(); - } - - $sum = md5(json_encode($data)); - if ($sum === $currSum) { - return; - } - - $this->syncedItemRequest->updateChecksum($syncedItemId, $sum); - } - - /** - * @param Circle $circle - * @param SyncedItem $syncedItem - * - * @throws FederatedEventException - * @throws FederatedItemException - * @throws InitiatorNotConfirmedException - * @throws OwnerNotFoundException - * @throws RemoteInstanceException - * @throws RemoteNotFoundException - * @throws RemoteResourceNotFoundException - * @throws RequestBuilderException - * @throws UnknownRemoteException - */ - private function broadcastItemUpdate(string $singleId): void { - $syncedItem = $this->syncedItemRequest->getSyncedItemFromSingleId($singleId); - - foreach ($this->getAffectedCircles($singleId) as $circle) { - $event = new FederatedEvent(ItemUpdate::class); - $event->setCircle($circle) - ->setSyncedItem($syncedItem); - - $this->debugService->info( - 'generating {`IFederatedEvent} using {event.class}', - $circle->getSingleId(), - [ - 'event' => $event, - 'syncedItem' => $syncedItem, - 'circle' => $circle - ] - ); - - // TODO: do not async for each circle as it should already on a async process! - $this->federatedEventService->newEvent($event); - } - } - +// $syncManager->syncItem( +// $syncedItem->getItemId(), +// $data +// ); - /** - * @param string $singleId - * - * @return Circle[] - * @throws RequestBuilderException - */ - private function getAffectedCircles(string $singleId): array { - $circleIds = array_map( - function (SyncedShare $share): string { - return $share->getCircleId(); - }, $this->syncedShareRequest->getshares($singleId) - ); + // update item based on current (old) checksum to confirm item was not already updated (race condition) + // do not update checksum +// $this->updateChecksum($syncedItem->getSingleId(), $data); - return $this->circleRequest->getCirclesByIds($circleIds); + return $data; } +// +// +// private function updateChecksum(string $syncedItemId, ?array $data = null): void { +// $currSum = ''; +// if (is_null($data)) { +// $knownItem = $this->getLocalSyncedItem($syncedItemId, true); +// $data = $knownItem->getSerialized(); +// $currSum = $knownItem->getChecksum(); +// } +// +// $sum = md5(json_encode($data)); +// if ($sum === $currSum) { +// return; +// } +// +// $this->syncedItemRequest->updateChecksum($syncedItemId, $sum); +// } /** @@ -567,16 +567,18 @@ public function updateSyncedItem(SyncedItem $syncedItem): void { /** * @param IFederatedUser $federatedUser * @param SyncedItem $syncedItem + * @param SyncedItemLock $syncedLock * @param array $extraData * - * @return array + * @return bool * @throws FederatedSyncManagerNotFoundException */ - private function isItemUpdatable( + private function isItemModifiable( IFederatedUser $federatedUser, SyncedItem $syncedItem, + SyncedItemLock $syncedLock, array $extraData = [] - ): array { + ): bool { $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); $this->debugService->info( 'sharing of SyncedItem {syncedItem.singleId} looks doable, calling {`isShareCreatable()} on {syncManager.class} for confirmation', @@ -588,29 +590,13 @@ private function isItemUpdatable( ] ); - try { - return $syncManager->isItemUpdatable( - $syncedItem->getItemId(), - $extraData, - $federatedUser - ); - } catch (Exception $e) { - $this->debugService->exception($e); -// $this->debugService->info( -// 'update of SyncedItem {!syncedItem.singleId} is blocked by {!syncedItem.appId}', -// '', -// [ -// 'federatedUser' => $federatedUser, -// 'syncedItem' => $syncedItem, -// 'extraData' => $extraData -// ] -// ); - // define Exception that can be thrown by app: - // - itemnotfound - // - ItemUpdateException - // - throw $e; - } + return $syncManager->isItemModifiable( + $syncedItem->getItemId(), + $syncedLock->getUpdateType(), + $syncedLock->getUpdateTypeId(), + $extraData, + $federatedUser + ); } @@ -708,4 +694,42 @@ private function compareWithKnownItemId(SyncedItem $syncedItem): void { } } + + /** + * @param SyncedItemLock $syncedLock + * + * @throws InvalidItemException + * @throws SyncedItemLockException + */ + private function manageLock( + SyncedItem $syncedItem, + SyncedItemLock $syncedLock, + ?string $remoteSum = null + ): void { + $locked = true; + for ($i = 0; $i < self::LOCK_RETRY_LIMIT; $i++) { + try { + $this->syncedItemLockRequest->clean(self::LOCK_TIMEOUT); + $this->syncedItemLockRequest->getSyncedItemLock($syncedLock); + sleep(1); + } catch (SyncedItemNotFoundException $e) { + $locked = false; + break; + } + } + + if (!is_null($remoteSum) && $syncedLock->isVerifyChecksum()) { + $known = $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); + if ($known->getChecksum() !== $remoteSum) { + throw new SyncedItemLockException('checksum is too old, sync required'); + } + } + + if ($locked) { + throw new SyncedItemLockException('item is currently lock, try again later'); + } + + $this->syncedItemLockRequest->save($syncedLock); + } + } diff --git a/lib/Service/GSUpstreamService.php b/lib/Service/GSUpstreamService.php index 7684f558a..3e24f2f31 100644 --- a/lib/Service/GSUpstreamService.php +++ b/lib/Service/GSUpstreamService.php @@ -287,7 +287,7 @@ private function isLocalEvent(GSEvent $event): bool { * @throws ModelException */ public function getEventsByToken(string $token): array { - return $this->eventWrapperRequest->getByToken($token); + return $this->eventWrapperRequest->getBroadcastByToken($token); } @@ -298,7 +298,7 @@ public function getEventsByToken(string $token): array { */ public function manageResults(string $token): void { try { - $wrappers = $this->eventWrapperRequest->getByToken($token); + $wrappers = $this->eventWrapperRequest->getBroadcastByToken($token); } catch (JsonException | ModelException $e) { return; } diff --git a/lib/Service/RemoteStreamService.php b/lib/Service/RemoteStreamService.php index 07ffb262f..0098c9e13 100644 --- a/lib/Service/RemoteStreamService.php +++ b/lib/Service/RemoteStreamService.php @@ -177,9 +177,9 @@ public function getAppSignatory(bool $generate = true, string $confirmKey = ''): ) ); - $app->setSyncItem($this->interfaceService->getCloudPath('circles.Remote.syncItem')); - $app->setSyncShare($this->interfaceService->getCloudPath('circles.Remote.syncShare')); - $app->setDebug($this->interfaceService->getCloudPath('circles.Remote.debugDaemon')); + $app->setSyncItem($this->interfaceService->getCloudPath('circles.Sync.syncItem')); + $app->setSyncShare($this->interfaceService->getCloudPath('circles.Sync.syncShare')); + $app->setDebug($this->interfaceService->getCloudPath('circles.Debug.debugDaemon')); if ($this->interfaceService->isCurrentInterfaceInternal()) { $app->setAliases(array_values(array_filter($this->interfaceService->getInterfaces(false)))); diff --git a/lib/Service/RemoteUpstreamService.php b/lib/Service/RemoteUpstreamService.php index e5346e845..d9c4d6cd1 100644 --- a/lib/Service/RemoteUpstreamService.php +++ b/lib/Service/RemoteUpstreamService.php @@ -31,9 +31,6 @@ namespace OCA\Circles\Service; -use OCA\Circles\Tools\Model\Request; -use OCA\Circles\Tools\Model\SimpleDataStore; -use OCA\Circles\Tools\Traits\TNCRequest; use OCA\Circles\Db\EventWrapperRequest; use OCA\Circles\Exceptions\FederatedItemException; use OCA\Circles\Exceptions\OwnerNotFoundException; @@ -44,6 +41,9 @@ use OCA\Circles\Model\Federated\EventWrapper; use OCA\Circles\Model\Federated\FederatedEvent; use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Tools\Model\Request; +use OCA\Circles\Tools\Model\SimpleDataStore; +use OCA\Circles\Tools\Traits\TNCRequest; /** * Class RemoteUpstreamService @@ -88,16 +88,6 @@ public function __construct( } - /** - * @param string $token - * - * @return EventWrapper[] - */ - public function getEventsByToken(string $token): array { - return $this->eventWrapperRequest->getByToken($token); - } - - /** * @param EventWrapper $wrapper * diff --git a/lib/Tools/Model/ReferencedDataStore.php b/lib/Tools/Model/ReferencedDataStore.php index b74c1ce3e..aff75e99a 100644 --- a/lib/Tools/Model/ReferencedDataStore.php +++ b/lib/Tools/Model/ReferencedDataStore.php @@ -62,8 +62,13 @@ class ReferencedDataStore implements IDeserializable, JsonSerializable { private array $data = []; private string $lock = IReferencedObject::class; - public function __construct(array $data = []) { - $this->data = $data; + public function __construct(array $mixed = []) { + foreach ($mixed as $k => $v) { + try { + $this->sMixed($k, $v); + } catch (InvalidItemException $e) { + } + } } @@ -101,6 +106,7 @@ public function g(string $key): string { public function u(string $key): self { if ($this->hasKey($key)) { unset($this->data[$key]); + unset($this->ref[$key]); } return $this; @@ -272,7 +278,7 @@ public function gObj(string $key): ?IDeserializable { * @return ReferencedDataStore * @throws InvalidItemException */ - public function sMixed(string $k, mixed $obj): self { + public function sMixed(string $k, $obj): self { if ($obj instanceof JsonSerializable) { return $this->sObj($k, $obj); } diff --git a/lib/Tools/Traits/TAsync.php b/lib/Tools/Traits/TAsync.php index 1a0b5de97..575fd61e8 100644 --- a/lib/Tools/Traits/TAsync.php +++ b/lib/Tools/Traits/TAsync.php @@ -36,9 +36,7 @@ trait TAsync { use TNCSetup; - - /** @var string */ - public static $SETUP_TIME_LIMIT = 'async_time_limit'; + public static string $SETUP_TIME_LIMIT = 'async_time_limit'; /** From fa0c9c1b15cfc1a7c8d817f626180a65de922bea Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Thu, 2 Jun 2022 11:21:22 -0100 Subject: [PATCH 4/5] lock, getOwner() and fixes Signed-off-by: Maxence Lange --- appinfo/routes.php | 3 +- drafts/flowchart_updateitem_31052022.png | Bin 0 -> 800954 bytes lib/CircleSharesManager.php | 28 ++- lib/CirclesManager.php | 10 + lib/Controller/SyncController.php | 64 +++++++ lib/Db/SyncedItemLockRequest.php | 4 +- .../FederatedSync/ShareCreation.php | 25 ++- lib/IFederatedSyncManager.php | 20 +- lib/Model/SyncedItemLock.php | 7 +- lib/Model/SyncedShare.php | 3 +- lib/Service/FederatedSyncItemService.php | 42 +++-- lib/Service/FederatedSyncShareService.php | 178 +++++++++++++++--- 12 files changed, 317 insertions(+), 67 deletions(-) create mode 100644 drafts/flowchart_updateitem_31052022.png diff --git a/appinfo/routes.php b/appinfo/routes.php index 91b835234..64a9738ef 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -118,7 +118,8 @@ ['name' => 'Sync#syncItem', 'url' => '/sync/item', 'verb' => 'GET'], ['name' => 'Sync#updateSyncedItem', 'url' => '/sync/item', 'verb' => 'PUT'], // ['name' => 'Remote#syncItem', 'url' => '/sync/item/{singleId}', 'verb' => 'GET'], - ['name' => 'Sync#syncShare', 'url' => '/sync/share', 'verb' => 'POST'], + ['name' => 'Sync#syncShare', 'url' => '/sync/share', 'verb' => 'GET'], + ['name' => 'Sync#createSyncedShare', 'url' => '/sync/share', 'verb' => 'PUT'], ['name' => 'Debug#debugDaemon', 'url' => '/debug', 'verb' => 'POST'] ] diff --git a/drafts/flowchart_updateitem_31052022.png b/drafts/flowchart_updateitem_31052022.png new file mode 100644 index 0000000000000000000000000000000000000000..266c8c56bc7796130555f45562733d1b43fff165 GIT binary patch literal 800954 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

fqN0c}1nA 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 z zKob~#%n>8OHr+(T?|24acLm0A^E}8_K`(4Moao&Hz%xB@ z1+Q1Qy36eSDKADm!!-cAgziNn7r#VLE~2GYztP~il^y0PMUD7nE>-PT4TyOx)`jAe z`1M?jWc@bIO3W;8RE%zhc#nU?txng{n>W6hbKYWtzXY6g8DJh?LP1>8GLg6r5MaPD zDak`@$a&gOIpVikMEhv{TgMp`_s&+>+da=L_E)?MxTyZl#YhW0TP|S#QHO77x?loX z#2u`yol=D9UUyu6dw^Cr*-6;bU3#^BwuRVNHG#8C3Nw|2$C8;t4XcVH6kr;}s+MEE z^kkj&SS+!AtDU`sD zB|`6HxHuR}Y_7%?O~eu*Gu$GFttH#=K;!kP4+ZMbgl(%I>igzZO9)zW?Cu}~M zkyt|6=J%pm40h1cCC=Amx5MyLujO`SE#u4o;Flz@Aw~gg+wqg)O(KQTPc6aSZ7dS~ zly^&J-D9>_x(b{>%Y<(0^ONe`r$*%5_1uPC@kd$xOg_sH7AoD-$EyR1#YgV9Q@AR~ z+{nnN0I12?Ia!NS3Ev;TYi0~bpiFyg3KKb4hzg8ApS~^3uAKHTk*8t2!R}sa=L}f!=nY|%4g~&#!4~_Tw2W*HapX0#bx-B3j?cv z7bl3`C$bEGZ{{T&?Q+)m4l7Tm|+9~69EF93$2BM=OpF7u# zYEQ`NwM(xGYG8~ffgKjkQCtXt4>~Ix6Q6kYpyn+H0H9>=roY?KthjRHtcUmN$nH?} z=1r6|!TOMS|3V;cdn8*8Xvwi8;{+qO0e1R9KSu|`%Et$x+ly$S6U9jpoMOhspL-46 zw#Qujc6^Y#auu?7BxMcHwKH@ZGq&h%?%H^EA5W^II5#6 zyn6gBu)xij4cd>bf~^Lpk`7ig^cF9sn6CdFsh8(%z0tQ+{YL2Kd-Qr;3E;FyfB@2T zfK9p>sbZO}J=a*4^jYS})LX>YpbtfbXIMf78vv!yigO`yGF#Vuy_Ssn5lQK0;7NON zKE9=ctB-QmAq8D$o7)iFYn<1JW!}tU$JLL>m0atU#SX}2j$iI(+05ye_;V$I7HsgUg?#iUATlKxd@)9 zZqn>{lI&`KP}2J$fQ%<@4Tt0SO1YZ-)&qB@JNeU%bLB>H2Ksg8z~O-eBdSXd`IoO# z^U>1D`e0nja*nzCL{yStOs`9VgEx3^^nZ?TzcQE{G%0ABT;16n2c2{fK-cya*sZM7 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�l4&q?*fKPkl)L&O86wPM@<0gF5AJ5E*D_t0gY9W2kb#m>%-)rLK)g(7D8 z0zFAtyjb6c{ysW-(*OOv|1?;z(!^y~W_BJ4OqGx-g4?M3tkYxXb1v*UlHR;IJJ1Z~ zhFSM{cHq69%EET*8AMjx3wtWCdNnwblWEm?R`wYl=jtB5EOidSB_6nx4c@Y8R1^F3 zq3!&W&Jy4;ouWRUs#U1Yd^6mn=IVvjT{m6*2-(!n*&fI!*;Gv?i>b9)%VN3M9!;HKbC*}+;!JuNJ>0?^6JkX|L?m1@*XbFG0u&>!mGBoqc7ux>((Si;4fE)MEOO_Q{?Ax<4jz0<3UH1j+ zGtRz;ygL;R5h5j^VE?JC37s5o0c@52j`zQ+L*A<%lXfGqG|n4~E=4W_#ybUH1>GLT zq$_oawz`XMtT4L?89t?Gagk~;L3A&B3&Qt8l2o(wljiuRT2sv?N>3Eqtg2dWVNHsy zMkG*cH1X&KS4G-b{f*v>wFbqh0q(M7Lg#WMmWO+vJQKACH^aw<$ONm5JAKErx1UJJ zOzJQ|`3A8sEA+c`Kt^$VeZ8zoQYw348<+WJy?J-hgV^OMYRB=a=UD#Q*h!&MF1#9# zPi$bCzS{N~kSCYIHq=SqXR6|wc%Y)e1ZB;5bL1D-D89U2be?GHEw9Aldv6E&OEF}p zsJOL(6k|8hK{LfD5p^-KCZXlRkA?a{=NAKk8PXncU9M@3hAJD4$2gA%D*>~lwEF1K zQE#)}Y&C#hM!!8m*w1!9a@)+1i1V=OiQs~Q3VqTB27DIV>zAoSwk?4=ySiMnU%8;9 z2s+c#-{$!@25A3MleC=cu7TdrlxPJy*u$ZTIy`O}?@Hq~++OzEdl0rsc7b`X;uLnr1T%vwZu099m1@&5ja!~Ea}xg^SMy9{ z$-6A2+;EiUw5{qlA(zWi5o6_(V=PQ(d#q9vtKlYPGe? zN^Ub&=m~!BW}vD7)^w#9A*hdLVRmJ_Tptl_hOx{K&{3}_eRB;j)Os5Q>dvBG~8C>`S;7GRBM>xMs zEvu&U^J@$<1fq*LOGTAn))k9-dKja-IXOB@)I;CtdG;bv0Zv4-KIeoYJmxnyC&#ol z%@(DOSMEA&sORKPS_)3*Jh$+#HcpF0nfP!*m6MEfR;B{k1+Z-+;Jq*$udA))<%~&@ zfohbW=bV5F8K0TR$$4aP{Nz1Ea%xU)^KQZwDb&Le9`OO*9F>7~TJsJLZkNEc(x7+N zHCdkkBj)5wfcuwx%;`uTJ;Y%uz$nka$(#h&# z+G7qTVU$AIuYFSu(1wTQ+hw)J2}W5Ai`J8(;|zW5T0|GuPNzik$5_mLPT2V{EMws2 zAn_eXd`2pK3bt38{^zn3$A=4-rJQ={$3e>E*~#@qdTIIA9o^+`qdObT98O`ZF6r7l z9`hr$Qq0V06Z7*?JHx(b>We(~VsB&}o(O3%cKOuOk~8Q-%(=x8zLAM&o*OS{kiw+p zM3VTeC7WIaCrHJ5$b}6FL!fHgnGN-M+8NPZOKpvo)mxC8c9dNyo*$G9&I55 zk;KX&!yy(m1TrX3-EHr=d3SEwtG6-KBGyr)dOhgCEgo#`?V_! z?0W*(9-acn;I*&Qk(ReBvj&RYxED8k;Ptl^GN4VDayA$2a&~u505d4)QtccN#gc9q zJ}Kt{H9^Q{YPa-jS47NP zgU%a4wTbR28WRqNa4bUN>E}y~*Vw-6sY4dr8FVcbs&*?f9TucoGZKX=r+vG~-CLm8 zGT`uO?IwoBy<)Y*g=Z_EgUYf-?#!ec<{Q6owHx>PbEtV|K}^k-eV~YMM6#ru4$Ifc zO89^$lWLA+&J|2u2am8&wGr+0Tc-}?wI@1Zrr$3n&DvRq#?qQ}MDt0SF2Y0qnWL9?q7XNI0eSIb) zjd6NsZKNH9hT)U4h|Sf2&J&!PE6rS`ue4~s69@lK{MScw*6euH9^s1k%DQ$l<2ZJ)cVG|@L5hl?bVn2np(sjkB27Ai^g3g~3K9^c zi&7*s>Al#fN|YAqC?!H@(p%uJlXHU1{B!?%^E@BIH#z6*z4j{ade=T{=iG1-6SSt0 zxW#1QU<-cGbf2*|0gpL(Z9iQ!_dO8vWvv**l@JlgR_3Q^du#bu+nv{KTd(wVG_Tx$ z>Fi&Br9|j$u72DoeyW0^z9`85^V!e7EEm>%YFNJ#PQPxsGZ`Ek!J!BhAT4kqWxX#V zZXIZjWTa?2rfT~?Nrrz^pW&itJYU92aJ$R=<5ZPKpo>meeF+CDF`kQ8ie4mYtsT>n zy&rKbJQ{0Hm0OAW2keNPB^seaqe zg)8=&`dBg@aT$KC!LRr405QDt7f7?Vp-;F_t)08M@!h=*BDNh|kJ#uwNPVR?l5=t( zi5;Lu+t($HbGIj-eKf5ZS&I4T-*JbRvn=J)Gpg@*H>CR}8!QbB9_Kp%lR5PU{4TNm z87E|xe)Y0`Tz~r^(<#$}Ht0#}9Q#fV%bJD!ZC`1TEqdK)B^IQd!!Y;hy__EF@=m~N z^vYg`8_fSH?*!l~Rlf3KBEwvf`~CdbX)&kyY~$9F--0%td1{wm$gyppq-{Y%o(}It%Uth=I5-qjU&PA#9j_4D3~ueE zRr99Z8QcH!Ifp}-sPVALxlIORqZ4(Xt_L5Ct_bM9Uzj7zDwU@)x$mSJIed;zPJS|OkB8s ze;?o!Kpk$>Ug$K>@gn{_vBTB%` zS>d@&81K-rM*v?S_0C{blq=qu#Z8oQfJH?Jn0HDTdr5-^`}=FOJB%h zo@yEIa1$eI!}=%?Z(Q^KTiRn@EoEj(7_aKDpG$&P_uyFdrlO$nfR|n&f8o?Cnl0s~ z%I=6qf!WdA?6r@%Hr=&~Qbcg)axH%KvB1gp1P3m>=bFupkYj+X zGjtM)JKChaH*c7)t^71{-Ey+O@KTmdKT$GTYnQy+(`XrIDk+DvNGWE7(zVkl!W91RjIOk zD^Z;relidC9_i26xbmp39RQ@!@5IHP`bt=>H9K_1T6;XuCXdF^K0A6rKyTu&jy>k; zjr+29)NvjsFO2S==i`*pE9GBOpO#*HzVEjaWZ??a%>LHZnLEel*0#@nx>Vr)DN{k( zQ=wBRBI%@DSnqIu99yx?N9PnEe-PNMw{^$!t$|bpVzA)cX`#)7FHn4Hhp!7`FKw8K znLaW&*D7MzF+JxXUu3G}b`i|0#~}BwcDj1%V5;=AT%ue`!JPSLU$?GAM7)QDY}xU3 z#98&*`i%sklG(p%Yw-G6UM$$TcAwrChIWwoS~+cy1j zc+Y68*TMo_GCK5yRF>H|xn^?i)tbgUts_$71Gk@%(qzICt2lo*?+J1pOKUyaX*5(- zUq2u+KIC|DKya`H_9i&qD&7+R`sSK7#;bdF2m`*BJmYs?K&9*g__^a14j;J@G=hBc z7J8-^R=(6BzidnE;RwwW&$s|uNYbm98uDB%@v5}VdO_6gRVM;4f8ohs)Nh@3{j%#Ouo{M3pDMJ0`Vfs|J$4 z)BMc_Nc)FBtx`Fclu_u*m3V1pGEA6TyVFx#UZB;nA>Y9aVHgrAtkX4;SN{fZvtwTq z;iL8%T6WBIqGxW>&~PK5-#+UW%aPiYvC%R02S+3jN7C$mtsyJ!_f70++Myh>c%G%t zZ<;SP{vgp9q@n5WBDW{<)axrGL-qU(k2en`_}i*Uc`rG-UHeiqF#UZk?D#+?>If$7 zWc}!paZ9oN^eDe-G@V3g5Khx-%xZ*&#AUnw6nE-*ma~wd3UK;GR*p1exl8e< zK9GHC-{JcYo5H15LcVEgY_>@j1_IX!X=4>2} z72ou0hJm}=>`UdFI97=pf2h17zVPr!8pvNa(ziG5n}*Wl{*(314LeL?6U^2K_uk;T z9_?h){8B%+GoiD)sn0D2sm0RolU$40@{pm|k5-NJimU7_wHUbGZXGr|x0ZFmGI!r^`T?Gc5%h`CiC`|h z=KKVNLJ=JwOMMP-dSK?W?ECd2>ju8aZu&KhN{Ry_M%-)SG1!-Q+gm`ReOmJ)FYe7b zRP37cbh+jP8TKs2`k6*2U4eMtLr=G@exaN-rO=69PF!E=1W5J%Wi!Lth*Rp%X}xdz zIpnwf$pAUHXU2Q)Y_-g6KFGy;?0UjLqvh8@BJL0W*w|8slA@WtR#%$UFP(rhfFH&l zt4&=Y=20PLDyHz)GO0jNU8sIfjD_7P4~pZfdJgTCyVu~H4(T;A^38`9Vx%N;uGNP{ zXPHl`>N!|?M@l%Wv)Q<=vR9^$=ORQ~(~q}9sr^IUNDg|@&8>hdvA{c0ccie;{iVet z0!w_gy{Leieuvsv1P`rke!COz>74Cg{cb`40z%V%m-T+3Odj zB-9cNo0s_Sy>K*Jee_9RwtM;{q3=6cVCl}8y?2iB9GPHbYYdCG^SpOYBC}Les? zbxms+vtaxb$eLKH>BB0k%&#^mFyQnv|kH0-N z#MC2IXPEt9@l%VwOJ-Lxnw4$ag zBMB1>az)oN?{?UvSL{~*m#;TlrfB4WhH*DnjUP2^GNV+%p)VORWk$4?q?Im-{^W6V;)kP9%3i zXwuikqV&tdn=`_;YDsyNq}x2qVKSNRH`=)L_~+~bPvy`jcj3&-{!pDrO&R&p8U zNSW_Hk}}hGsd((2_eAU5&H;zc7x`!66;us9YyDqH@qhpFQAUUo`_=y%+=|z!ssbTj z8ZFx{$4I3i%u_)IA@7?y{iQPxyvmj2^$Aed_qR*M@$o4)9~5^I5+!5+SAQj-g5a(> z`f$+fh!%$;9`7xY$%VV1TGy$aVVtpM>~;O|sg#K(VDcy5xAlvM1c%Y+pazrgzVwq?k6s9r-&hAUr6d3KQvI+W`NIcJ zU0$=)l2V_b{6&ujY$RY%%eLhA7InwZ+xqQ$eqCj%9+uhd`oNlkc(OMfLCMu$T`MI5 z978{qY}pn_pBVbPxu9YpB6URK+1Y7#6Ka&3m}x+f2kF|vt2Gnl8*Zu@a-DQ260i#QgDfl=~PEIrv*i|q>BV%!(>?a3%(I1*nYqJqqiQ4efPrKq?@qoMUBYSgb z%n+-L3tFzGbA1W7-6MB8bf?ByXy*73&M7xp6fSSZnu{}T7yF#PV+Xnxf?9nBFa2xX zSZ}DYXK$hny}OU2$YMP-PWKngh{bcw&NT(4*(#|es$ME7SyU!%EbBdZ?7DpFr?>;< zri*nCte|YV74c+TRYxCw*(+?StG7#JmzrthR-!RD0|D4RnrZpd4+CGo#LLR3*KWVy zaSNjcgC4zn`LgW8>A=%wlwWbgZHkBLWv9+O$S5&@&=wvLkS>W(Xu|7PoO&ypS#L;r9au{*Kx^?ZjZGRTEI=;)N@k0Gxg=$E3>!`PpS}_Vd~pd2^%*)m}cJidh(AWUcFcGs<2&LIhl0hHy{b(yjvpl zH-!VAY3i_{R#PZ@_>-Cu`%sdfRGP-LrR{b5C*1x_6~LW7#`RP& zK8axmE443g^YY@K)@MMobgi`I#lP5p7miv8P}=z3Rx^^`;&I8{x;;;BM0qi7&Uf`d z&SsIx^7EN~hlXpUYfWJvby)O?t7VS{w)Z3~8vYeF_T~y}OY|T3mRvL6sN$2VrO7kO zX`72x`odc*q1a7~eQ|Hzc<)KYRR?u=Gwua=TGdXnrpOW@yUCha^?sLi;t>qJi9d@TzHs*QuvTb=M^k8e=bt9{5*Ish)o+0`zWM6_Zhf_D8q~x9h zVtFc^f-V{-JLs=0D7ML*Yo_}l_qawY7a?iCHJE-HeW}|tC2Oqpw)o>w-!pIB5>-u{ zt!GW*4oOO!=8#HNE9Kza(Z;QdWZJY~&$v&o^v9C)FKr6X`t%xJxs7*c`#i)Vo%;J< z8sB?<7(qz;g*)<8YT-vR$+`43Nh_fwSYTFjokT7l*Pu4+#Sqh#w;0>2W#F#7fvR{Z zt#w3WsY3s;Z$gN)3sp_c$ypd!Q92-!eQmf^Ja3w1 zwe!6T5H6kO>-q9B58Cz%sR%{ucCVQpZpz(YdSt9=5h?j=d0aO6o2fp}zV&}e@3tnk zn3d@6*u8r?NtpIa1nllVaVFGznA3a~Ht4NedF(4s(lTazECZMk$Wwx97T5bUU4Fd9 z{-)M@YEM#2{kaB$fx+&4!P(QNj*l@czFcf-jcj{(;X9QC31-W}xIMxIutPvv6ZOQE-4X-yu-2bv82YAapX>S z0?(rK!A?>mYijqj5-n?irZU-SK8_@+$0>#CA{LbTxi7Xi7J_BxET^5`r|6S*CwRR) z^7k1o{A)c<;7U}}q&=g(I`SfsB{RG2jPPVPdfffFE;({fGQvO8dd%}Bm-u@mLVk}nQ z-Pw>XUqW*#?lV=2D&?2(;3YtrHz=5x>|j=Z|8fOXvH^CUcX~yHGe2X(mxRw732acy zRQ5#lkTg$e`tiay%T>>6O2(IE@JT{QE)-9%=LxOZ=4AeDoP|J)+A|&u;_4ku@7>Fs z&FS|hnaxwCp4NNho(Ws72w1p0&A2xS=+w%ZlhtW^GMoAFpX+XKImBFCw!o^CvgyLf zf^$0EP1ov1{|YACs=U;=ka z#AO@lv>h1)%0Dc9d0EVu=d?yIR;; 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

e#If6|Cn* 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�$Csx0&w^ETvkgDN%rt;Mz}>$ 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 z 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 ST1)6&`WKCV!koW;|GxtGC%|d| literal 0 HcmV?d00001 diff --git a/lib/CircleSharesManager.php b/lib/CircleSharesManager.php index 59973b4d9..cc4eae6c8 100644 --- a/lib/CircleSharesManager.php +++ b/lib/CircleSharesManager.php @@ -33,7 +33,6 @@ use Exception; use OCA\Circles\Exceptions\CircleSharesManagerException; -use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Model\SyncedItemLock; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; @@ -145,12 +144,12 @@ public function createShare( try { $this->mustHaveOrigin(); - // TODO: verify rules that apply when sharing to a circle - $probe = new CircleProbe(); - $probe->includeSystemCircles() - ->mustBeMember(); - - $circle = $this->circleService->getCircle($circleId, $probe); + // TODO: do we need this here as we are also checking federatedUser during isShareCreatable() +// $probe = new CircleProbe(); +// $probe->includeSystemCircles() +// ->mustBeMember(); +// +// $circle = $this->circleService->getCircle($circleId, $probe); // get valid SyncedItem based on appId, itemType, itemId $syncedItem = $this->federatedSyncItemService->initSyncedItem( @@ -163,20 +162,19 @@ public function createShare( $this->debugService->info( 'initiating the process of sharing {syncedItem.singleId} to {circle.id}', $circleId, [ - 'circle' => $circle, + 'circleId' => $circleId, 'syncedItem' => $syncedItem, 'extraData' => $extraData, 'isLocal' => $syncedItem->isLocal() ] ); - // confirm item is local - if (!$syncedItem->isLocal()) { - // TODO: sharing a remote item - return; - } - - $this->federatedSyncShareService->createShare($syncedItem, $circle, $extraData); + $this->federatedSyncShareService->requestSyncedShareCreation( + $this->federatedUserService->getCurrentEntity(), + $syncedItem, + $circleId, + $extraData + ); } catch (Exception $e) { $this->debugService->exception($e, $circleId); throw $e; diff --git a/lib/CirclesManager.php b/lib/CirclesManager.php index e375dd8c1..39bea304f 100644 --- a/lib/CirclesManager.php +++ b/lib/CirclesManager.php @@ -59,6 +59,7 @@ use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; +use OCA\Circles\Service\DebugService; use OCA\Circles\Service\FederatedUserService; use OCA\Circles\Service\MemberService; use OCA\Circles\Service\MembershipService; @@ -74,6 +75,7 @@ class CirclesManager { private MembershipService $membershipService; private ConfigService $configService; private CirclesQueryHelper $circlesQueryHelper; + private DebugService $debugService; /** @@ -94,6 +96,7 @@ public function __construct( MemberService $memberService, MembershipService $membershipService, ConfigService $configService, + DebugService $debugService, CirclesQueryHelper $circlesQueryHelper ) { $this->circleSharesManager = $circleSharesManager; @@ -102,6 +105,7 @@ public function __construct( $this->memberService = $memberService; $this->membershipService = $membershipService; $this->configService = $configService; + $this->debugService = $debugService; $this->circlesQueryHelper = $circlesQueryHelper; } @@ -269,6 +273,12 @@ public function getQueryHelper(): CirclesQueryHelper { return $this->circlesQueryHelper; } + /** + * @return DebugService + */ + public function getDebugService(): DebugService { + return $this->debugService; + } /** * @param string $name diff --git a/lib/Controller/SyncController.php b/lib/Controller/SyncController.php index fd1f82dc6..30b65f304 100644 --- a/lib/Controller/SyncController.php +++ b/lib/Controller/SyncController.php @@ -187,4 +187,68 @@ public function updateSyncedItem(): DataResponse { exit(); } + + /** + * @PublicPage + * @NoCSRFRequired + * + * @return DataResponse + */ + public function createSyncedShare(): DataResponse { + try { + /** @var SyncedWrapper $wrapper */ + $wrapper = $this->signedControllerService->extractObjectFromRequest( + SyncedWrapper::class, + $signed + ); + + $this->debugService->info( + '{instance} is requesting the creation of a new SyncedShare on SyncedItem {syncedWrapper.syncedShare.singleId}', + '', + [ + 'instance' => $signed->getOrigin(), + 'syncedWrapper' => $wrapper + ] + ); + + if (!$wrapper->hasShare() || !$wrapper->hasFederatedUser()) { + throw new FederatedItemBadRequestException(); + } + + $syncedShare = $wrapper->getshare(); + $local = $this->federatedSyncItemService->getLocalSyncedItem($syncedShare->getSingleId()); + + // confirm that remote is in a circle with a share on the item + $this->federatedSyncShareService->confirmRemoteInstanceAccess( + $syncedShare->getSingleId(), + $signed->getOrigin() + ); + + $this->debugService->info( + 'SyncedItem exists, is local, and {instance} have access to the SyncedItem.', '', + [ + 'instance' => $signed->getOrigin(), + 'local' => $local, + ] + ); + + $this->asyncService->setSplittable(true); + $this->federatedSyncShareService->requestSyncedShareCreation( + $wrapper->getFederatedUser(), + $local, + $wrapper->getShare()->getCircleId(), + $wrapper->getExtraData(), + ); + + if (!$this->asyncService->isAsynced()) { + return new DataResponse(['success' => true]); + } + } catch (Exception $e) { + $this->e($e); + + return $this->signedControllerService->exceptionResponse($e, Http::STATUS_UNAUTHORIZED); + } + + exit(); + } } diff --git a/lib/Db/SyncedItemLockRequest.php b/lib/Db/SyncedItemLockRequest.php index b335ac8d3..6c570e8f5 100644 --- a/lib/Db/SyncedItemLockRequest.php +++ b/lib/Db/SyncedItemLockRequest.php @@ -46,8 +46,6 @@ class SyncedItemLockRequest extends SyncedItemLockRequestBuilder { /** * @param SyncedItemLock $lock - * - * @throws InvalidIdException */ public function save(SyncedItemLock $lock): void { $qb = $this->getSyncedItemLockInsertSql(); @@ -55,7 +53,7 @@ public function save(SyncedItemLock $lock): void { ->setValue('update_type_id', $qb->createNamedParameter($lock->getUpdateTypeId())) ->setValue('time', $qb->createNamedParameter(time())); - $qb->execute(); + $qb->executeStatement(); } diff --git a/lib/FederatedItems/FederatedSync/ShareCreation.php b/lib/FederatedItems/FederatedSync/ShareCreation.php index 6f2ab4fdd..5f110bcb4 100644 --- a/lib/FederatedItems/FederatedSync/ShareCreation.php +++ b/lib/FederatedItems/FederatedSync/ShareCreation.php @@ -37,9 +37,11 @@ use OCA\Circles\IFederatedItem; use OCA\Circles\IFederatedItemAsyncProcess; use OCA\Circles\IFederatedItemHighSeverity; +use OCA\Circles\IFederatedItemInitiatorCheckNotRequired; use OCA\Circles\IFederatedItemLimitedToInstanceWithMember; use OCA\Circles\IFederatedItemSyncedItem; use OCA\Circles\Model\Federated\FederatedEvent; +use OCA\Circles\Model\FederatedUser; use OCA\Circles\Service\ConfigService; use OCA\Circles\Service\DebugService; use OCA\Circles\Service\FederatedSyncItemService; @@ -52,6 +54,7 @@ class ShareCreation implements IFederatedItemLimitedToInstanceWithMember, IFederatedItemHighSeverity, IFederatedItemAsyncProcess, + IFederatedItemInitiatorCheckNotRequired, IFederatedItemSyncedItem { use TDeserialize; @@ -113,6 +116,21 @@ public function manage(FederatedEvent $event): void { } $circle = $event->getCircle(); + if (!$circle->hasInitiator()) { + $this->debugService->info( + '{?Initiator not available}', '', + ['circle' => $circle] + ); + + return; + } + + // note that we have no confirmation about the origin and/or memberships of FederatedUser at + // this point as this class implements IFederatedItemInitiatorCheckNotRequired + // the only use of this IFederatedItem is to broadcast an eventual new share which needs + // to be confirmed with a direct request to the instance that owns the shared item + $federatedUser = new FederatedUser(); + $federatedUser->importFromIFederatedUser($circle->getInitiator()); $syncedItem = $event->getSyncedItem(); $this->federatedSyncItemService->compareWithKnownItem($syncedItem, true); @@ -120,7 +138,12 @@ public function manage(FederatedEvent $event): void { $extraData = $event->getParams()->gArray('extraData'); $this->federatedSyncItemService->updateSyncedItem($syncedItem); - $this->federatedSyncShareService->syncShareCreation($syncedItem, $circle, $extraData); + $this->federatedSyncShareService->syncShareCreation( + $federatedUser, + $syncedItem, + $circle->getSingleId(), + $extraData + ); } diff --git a/lib/IFederatedSyncManager.php b/lib/IFederatedSyncManager.php index 725421b97..08ed3d332 100644 --- a/lib/IFederatedSyncManager.php +++ b/lib/IFederatedSyncManager.php @@ -112,6 +112,25 @@ public function serializeItem(string $itemId): array; public function syncItem(string $itemId, array $serializedData): void; + /** + * This method is called when Circles needs to confirm itemId is linked to an existing item + * + * @param string $itemId + * + * @return bool + */ + public function itemExists(string $itemId): bool; + + /** + * Method is called when Circles needs to know the owner of an item. Must returns a singleId. + * + * @param string $itemId + * + * @return mixed + */ + public function getOwner(string $itemId): string; + + /** * Your app returns details about a share. * Method will be called to re-sync a share on a remote instance @@ -315,5 +334,4 @@ public function onItemModification( IFederatedUser $federatedUser ): void; - } diff --git a/lib/Model/SyncedItemLock.php b/lib/Model/SyncedItemLock.php index 5ace71e68..33a94a337 100644 --- a/lib/Model/SyncedItemLock.php +++ b/lib/Model/SyncedItemLock.php @@ -32,7 +32,6 @@ namespace OCA\Circles\Model; use JsonSerializable; -use OCA\Circles\Exceptions\ShareTokenNotFoundException; use OCA\Circles\Tools\Db\IQueryRow; use OCA\Circles\Tools\Exceptions\InvalidItemException; use OCA\Circles\Tools\IDeserializable; @@ -199,11 +198,11 @@ public function import(array $data): IDeserializable { * @param string $prefix * * @return IQueryRow - * @throws ShareTokenNotFoundException + * @throws InvalidItemException */ public function importFromDatabase(array $data, string $prefix = ''): IQueryRow { - if ($this->get($prefix . 'token', $data) === '') { - throw new ShareTokenNotFoundException(); + if ($this->getInt($prefix . 'time', $data) < 1) { + throw new InvalidItemException(); } $this->setUpdateType($this->get($prefix . 'update_type', $data)); diff --git a/lib/Model/SyncedShare.php b/lib/Model/SyncedShare.php index 8c2e7afef..4d1f8cd0d 100644 --- a/lib/Model/SyncedShare.php +++ b/lib/Model/SyncedShare.php @@ -113,7 +113,8 @@ public function getCircleId(): string { * @throws InvalidItemException */ public function import(array $data): IDeserializable { - if ($this->getInt('singleId', $data) === 0) { + if ($this->get('singleId', $data) === '' + || $this->get('circleId', $data) === '') { throw new InvalidItemException(); } diff --git a/lib/Service/FederatedSyncItemService.php b/lib/Service/FederatedSyncItemService.php index 9fc677f04..7bf81fab8 100644 --- a/lib/Service/FederatedSyncItemService.php +++ b/lib/Service/FederatedSyncItemService.php @@ -30,6 +30,7 @@ namespace OCA\Circles\Service; +use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Exception; use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\RemoteRequest; @@ -260,9 +261,8 @@ public function initSyncedItem( 'itemId' => $itemId ] ); - try { - $syncManager->serializeItem($itemId); - } catch (Exception $e) { + + if (!$syncManager->itemExists($itemId)) { throw new FederatedSyncConflictException( 'SyncedItem not found in database and does not appears to be local' ); @@ -311,7 +311,7 @@ public function requestSyncedItemUpdate( ); return; - } else if (is_null($remoteSum)) { + } else if (is_null($remoteSum)) { // this means that the request is not coming from remote location $this->requestSyncedItemUpdateRemote($federatedUser, $syncedItem, $syncedLock, $extraData); return; @@ -360,6 +360,7 @@ private function requestSyncedItemUpdateLocal( // $syncedItem->getItemId(), // $item // ); + $this->asyncService->splitArray(['success' => true]); $syncManager->onItemModification( $syncedItem->getItemId(), @@ -370,7 +371,6 @@ private function requestSyncedItemUpdateLocal( ); // this should split the process and give back hand if request is coming from a remote instance - $this->asyncService->splitArray(['success' => true]); $this->asyncService->asyncInternal( AsyncItemUpdate::class, @@ -389,7 +389,7 @@ private function requestSyncedItemUpdateRemote( SyncedItem $syncedItem, SyncedItemLock $syncedLock, array $extraData = [] - ): array { + ): void { $wrapper = new SyncedWrapper($federatedUser, $syncedItem, $syncedLock, null, $extraData); $this->interfaceService->setCurrentInterfaceFromInstance($syncedItem->getInstance()); $data = $this->remoteStreamService->resultRequestRemoteInstance( @@ -420,11 +420,9 @@ private function requestSyncedItemUpdateRemote( // update item based on current (old) checksum to confirm item was not already updated (race condition) // do not update checksum // $this->updateChecksum($syncedItem->getSingleId(), $data); - - return $data; } -// -// + + // private function updateChecksum(string $syncedItemId, ?array $data = null): void { // $currSum = ''; // if (is_null($data)) { @@ -579,6 +577,7 @@ private function isItemModifiable( SyncedItemLock $syncedLock, array $extraData = [] ): bool { +// $federatedUser $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); $this->debugService->info( 'sharing of SyncedItem {syncedItem.singleId} looks doable, calling {`isShareCreatable()} on {syncManager.class} for confirmation', @@ -700,14 +699,16 @@ private function compareWithKnownItemId(SyncedItem $syncedItem): void { * * @throws InvalidItemException * @throws SyncedItemLockException + * @throws SyncedItemNotFoundException */ private function manageLock( SyncedItem $syncedItem, SyncedItemLock $syncedLock, - ?string $remoteSum = null + ?string $remoteSum = null, + bool $lastTry = false ): void { $locked = true; - for ($i = 0; $i < self::LOCK_RETRY_LIMIT; $i++) { + for ($i = 0; $i < (($lastTry) ? 2 : self::LOCK_RETRY_LIMIT); $i++) { try { $this->syncedItemLockRequest->clean(self::LOCK_TIMEOUT); $this->syncedItemLockRequest->getSyncedItemLock($syncedLock); @@ -718,6 +719,10 @@ private function manageLock( } } + if ($locked) { + throw new SyncedItemLockException('item is currently lock, try again later'); + } + if (!is_null($remoteSum) && $syncedLock->isVerifyChecksum()) { $known = $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); if ($known->getChecksum() !== $remoteSum) { @@ -725,11 +730,16 @@ private function manageLock( } } - if ($locked) { - throw new SyncedItemLockException('item is currently lock, try again later'); + try { + $this->syncedItemLockRequest->save($syncedLock); + } catch (UniqueConstraintViolationException $e) { + // in case of race condition between the check of lock and the save of a new one. + if (!$lastTry) { + $this->manageLock($syncedItem, $syncedLock, $remoteSum, true); + } else { + throw new SyncedItemLockException('too many request at the same time, try again later'); + } } - - $this->syncedItemLockRequest->save($syncedLock); } } diff --git a/lib/Service/FederatedSyncShareService.php b/lib/Service/FederatedSyncShareService.php index 9fa323ca8..1199f0a8e 100644 --- a/lib/Service/FederatedSyncShareService.php +++ b/lib/Service/FederatedSyncShareService.php @@ -30,37 +30,50 @@ namespace OCA\Circles\Service; +use OCA\Circles\Db\CircleRequest; use OCA\Circles\Db\MemberRequest; +use OCA\Circles\Db\MembershipRequest; use OCA\Circles\Db\RemoteRequest; use OCA\Circles\Db\SyncedItemRequest; use OCA\Circles\Db\SyncedShareRequest; +use OCA\Circles\Exceptions\CircleNotFoundException; use OCA\Circles\Exceptions\FederatedEventException; use OCA\Circles\Exceptions\FederatedItemException; +use OCA\Circles\Exceptions\FederatedSyncConflictException; use OCA\Circles\Exceptions\FederatedSyncManagerNotFoundException; +use OCA\Circles\Exceptions\FederatedSyncPermissionException; +use OCA\Circles\Exceptions\FederatedSyncRequestException; use OCA\Circles\Exceptions\InitiatorNotConfirmedException; +use OCA\Circles\Exceptions\InvalidIdException; +use OCA\Circles\Exceptions\MembershipNotFoundException; use OCA\Circles\Exceptions\OwnerNotFoundException; use OCA\Circles\Exceptions\RemoteInstanceException; use OCA\Circles\Exceptions\RemoteNotFoundException; use OCA\Circles\Exceptions\RemoteResourceNotFoundException; use OCA\Circles\Exceptions\RequestBuilderException; -use OCA\Circles\Exceptions\SyncedItemNotFoundException; use OCA\Circles\Exceptions\SyncedSharedAlreadyExistException; use OCA\Circles\Exceptions\SyncedShareNotFoundException; use OCA\Circles\Exceptions\UnknownRemoteException; use OCA\Circles\FederatedItems\FederatedSync\ShareCreation; +use OCA\Circles\IFederatedUser; use OCA\Circles\Model\Circle; use OCA\Circles\Model\Federated\FederatedEvent; -use OCA\Circles\Model\FederatedUser; +use OCA\Circles\Model\Federated\RemoteInstance; +use OCA\Circles\Model\Probes\CircleProbe; use OCA\Circles\Model\SyncedItem; use OCA\Circles\Model\SyncedShare; +use OCA\Circles\Model\SyncedWrapper; use OCA\Circles\Tools\ActivityPub\NCSignature; +use OCA\Circles\Tools\Model\Request; use OCA\Circles\Tools\Model\SimpleDataStore; use OCA\Circles\Tools\Traits\TStringTools; class FederatedSyncShareService extends NCSignature { use TStringTools; + private CircleRequest $circleRequest; private MemberRequest $memberRequest; + private MembershipRequest $membershipRequest; private SyncedItemRequest $syncedItemRequest; private SyncedShareRequest $syncedShareRequest; private RemoteRequest $remoteRequest; @@ -72,6 +85,8 @@ class FederatedSyncShareService extends NCSignature { /** + * @param CircleRequest $circleRequest + * @param MemberRequest $memberRequest * @param SyncedItemRequest $syncedItemRequest * @param SyncedShareRequest $syncedShareRequest * @param RemoteRequest $remoteRequest @@ -82,7 +97,9 @@ class FederatedSyncShareService extends NCSignature { * @param DebugService $debugService */ public function __construct( + CircleRequest $circleRequest, MemberRequest $memberRequest, + MembershipRequest $membershipRequest, SyncedItemRequest $syncedItemRequest, SyncedShareRequest $syncedShareRequest, RemoteRequest $remoteRequest, @@ -92,7 +109,9 @@ public function __construct( InterfaceService $interfaceService, DebugService $debugService ) { + $this->circleRequest = $circleRequest; $this->memberRequest = $memberRequest; + $this->membershipRequest = $membershipRequest; $this->syncedItemRequest = $syncedItemRequest; $this->syncedShareRequest = $syncedShareRequest; $this->remoteRequest = $remoteRequest; @@ -106,27 +125,88 @@ public function __construct( /** * search for existing shares in circles_share based on itemSingleId, circleId. * + * @param IFederatedUser $federatedUser * @param SyncedItem $syncedItem - * @param Circle $circle + * @param string $circleId * @param array $extraData + * @param bool $fromRemote * + * @throws CircleNotFoundException + * @throws FederatedEventException + * @throws FederatedItemException + * @throws FederatedSyncConflictException + * @throws FederatedSyncManagerNotFoundException + * @throws FederatedSyncRequestException + * @throws InitiatorNotConfirmedException + * @throws OwnerNotFoundException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RequestBuilderException * @throws SyncedSharedAlreadyExistException + * @throws UnknownRemoteException + */ + public function requestSyncedShareCreation( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + string $circleId, + array $extraData = [], + bool $fromRemote = false + ): void { + if ($syncedItem->isLocal()) { + $this->requestSyncedShareCreationLocal($federatedUser, $syncedItem, $circleId, $extraData); + + return; + } else if (!$fromRemote) { + $this->requestSyncedShareCreationRemote($federatedUser, $syncedItem, $circleId, $extraData); + + return; + } + + throw new FederatedSyncConflictException(); + } + + + /** * @throws FederatedSyncManagerNotFoundException + * @throws SyncedSharedAlreadyExistException + * @throws CircleNotFoundException + * @throws RemoteResourceNotFoundException + * @throws RemoteInstanceException + * @throws OwnerNotFoundException + * @throws InitiatorNotConfirmedException + * @throws FederatedItemException + * @throws RequestBuilderException + * @throws FederatedEventException + * @throws RemoteNotFoundException + * @throws UnknownRemoteException */ - public function createShare(SyncedItem $syncedItem, Circle $circle, array $extraData = []) { - if (!$this->isShareCreatable($syncedItem, $circle, $extraData)) { + public function requestSyncedShareCreationLocal( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + string $circleId, + array $extraData = [] + ): void { + + // TODO: verify rules that apply when sharing to a circle + $probe = new CircleProbe(); + $probe->includeSystemCircles() + ->mustBeMember(); + $circle = $this->circleRequest->getCircle($circleId, $federatedUser, $probe); + + if (!$this->isShareCreatable($federatedUser, $syncedItem, $circleId, $extraData)) { $this->debugService->info( - 'share of SyncedItem {!syncedItem.singleId} to {!circle.id} is set as not creatable by {!syncedItem.appId}', - $circle->getSingleId(), + 'share of SyncedItem {!syncedItem.singleId} to {!circleId} is set as not creatable by {!syncedItem.appId}', + $circleId, [ 'syncedItem' => $syncedItem, - 'circle' => $circle, + 'circleId' => $circleId, 'extraData' => $extraData ] ); } - $this->syncShareCreation($syncedItem, $circle, $extraData); + $this->syncShareCreation($federatedUser, $syncedItem, $circleId, $extraData); $this->broadcastShareCreation($syncedItem, $circle, $extraData); $this->debugService->info( @@ -135,23 +215,59 @@ public function createShare(SyncedItem $syncedItem, Circle $circle, array $extra } + private function requestSyncedShareCreationRemote( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + string $circleId, + array $extraData = [] + ): void { + $syncedShare = new SyncedShare(); + $syncedShare->setSingleId($syncedItem->getSingleId()) + ->setCircleId($circleId); + + $wrapper = new SyncedWrapper($federatedUser, null, null, $syncedShare, $extraData); + $this->interfaceService->setCurrentInterfaceFromInstance($syncedItem->getInstance()); + $data = $this->remoteStreamService->resultRequestRemoteInstance( + $syncedItem->getInstance(), + RemoteInstance::SYNC_SHARE, + Request::TYPE_PUT, + $wrapper + ); + + if (!$this->getBool('success', $data)) { + throw new FederatedSyncRequestException(); + } + + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + $syncManager->onShareCreation( + $syncedItem->getItemId(), + $syncedShare->getCircleId(), + $extraData, + $federatedUser + ); + } + /** + * @param IFederatedUser $federatedUser * @param SyncedItem $syncedItem - * @param Circle $circle + * @param string $circleId * @param array $extraData * * @throws FederatedSyncManagerNotFoundException + * @throws InvalidIdException */ - public function syncShareCreation(SyncedItem $syncedItem, Circle $circle, array $extraData = []): void { + public function syncShareCreation( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + string $circleId, + array $extraData = [] + ): void { $syncedShare = new SyncedShare(); $syncedShare->setSingleId($syncedItem->getSingleId()) - ->setCircleId($circle->getSingleId()); + ->setCircleId($circleId); $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); - $federatedUser = new FederatedUser(); - $federatedUser->importFromIFederatedUser($circle->getInitiator()); - $this->debugService->info( 'calling {`onShareCreation()} on {syncManager}', $syncedShare->getCircleId(), @@ -160,7 +276,6 @@ public function syncShareCreation(SyncedItem $syncedItem, Circle $circle, array 'syncedItem' => $syncedItem, 'syncedShare' => $syncedShare, 'extraData' => $extraData, - 'initiator' => $circle->getInitiator(), 'federatedUser' => $federatedUser ] ); @@ -175,10 +290,10 @@ public function syncShareCreation(SyncedItem $syncedItem, Circle $circle, array $this->syncedShareRequest->save($syncedShare); $this->debugService->info( 'storing SyncedShare of {syncedShare.singleId} to {syncedShare.circleId} in database', - $circle->getSingleId(), + $circleId, [ 'syncedItem' => $syncedItem, - 'circle' => $circle, + 'circleId' => $circleId, 'syncedShare' => $syncedShare ] ); @@ -229,26 +344,39 @@ private function broadcastShareCreation( * - SyncedShare is not already known * - app agree on creating this share * + * @param IFederatedUser $federatedUser * @param SyncedItem $syncedItem - * @param Circle $circle + * @param string $circleId * @param array $extraData * * @return bool * @throws FederatedSyncManagerNotFoundException + * @throws FederatedSyncPermissionException * @throws SyncedSharedAlreadyExistException */ - private function isShareCreatable(SyncedItem $syncedItem, Circle $circle, array $extraData = []): bool { + private function isShareCreatable( + IFederatedUser $federatedUser, + SyncedItem $syncedItem, + string $circleId, + array $extraData = [] + ): bool { try { - $this->syncedShareRequest->getShare($syncedItem->getSingleId(), $circle->getsingleId()); + $this->syncedShareRequest->getShare($syncedItem->getSingleId(), $circleId); throw new SyncedSharedAlreadyExistException('share already exists'); } catch (SyncedShareNotFoundException $e) { } - $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + $ownerId = $syncManager->getOwner($syncedItem->getItemId()); + try { + $member = $this->membershipRequest->getMembership($circleId, $ownerId); + } catch (MembershipNotFoundException $e) { + throw new FederatedSyncPermissionException('owner of Item is not member of Circle'); + } + $this->debugService->info( 'sharing of SyncedItem {syncedItem.singleId} looks doable, calling {`isShareCreatable()} on {syncManager.class} for confirmation', - $circle->getSingleId(), + $circleId, [ 'syncedItem' => $syncedItem, 'syncManager' => ['class' => get_class($syncManager)] @@ -257,9 +385,9 @@ private function isShareCreatable(SyncedItem $syncedItem, Circle $circle, array return $syncManager->isShareCreatable( $syncedItem->getItemId(), - $circle->getSingleId(), + $circleId, $extraData, - $circle->getInitiator()->getInheritedBy() + $federatedUser ); } From 8995bbe5c9942c9bfe446c77a49a054ea2cf3018 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Fri, 3 Jun 2022 14:06:44 -0100 Subject: [PATCH 5/5] debug Signed-off-by: Maxence Lange --- lib/CircleSharesManager.php | 41 +++--- lib/Service/DebugService.php | 2 +- lib/Service/FederatedSyncItemService.php | 153 +++++++++++++++++------ 3 files changed, 139 insertions(+), 57 deletions(-) diff --git a/lib/CircleSharesManager.php b/lib/CircleSharesManager.php index cc4eae6c8..7a74db845 100644 --- a/lib/CircleSharesManager.php +++ b/lib/CircleSharesManager.php @@ -33,6 +33,7 @@ use Exception; use OCA\Circles\Exceptions\CircleSharesManagerException; +use OCA\Circles\Exceptions\FederatedUserNotFoundException; use OCA\Circles\Model\SyncedItemLock; use OCA\Circles\Service\CircleService; use OCA\Circles\Service\ConfigService; @@ -133,30 +134,24 @@ public function createShare( ): void { $this->debugService->setDebugType('federated_sync'); $this->debugService->info( - '{~New request to create a SyncedShare} based on {appId}.{itemType}.{itemId}', $circleId, [ - 'appId' => $this->originAppId, - 'itemType' => $this->originItemType, - 'itemId' => $itemId, - 'extraData' => $extraData - ] + '{~New request to create a SyncedShare} based on {appId}.{itemType}.{itemId}', + $circleId, + [ + 'appId' => $this->originAppId, + 'itemType' => $this->originItemType, + 'itemId' => $itemId, + 'extraData' => $extraData + ] ); try { $this->mustHaveOrigin(); - // TODO: do we need this here as we are also checking federatedUser during isShareCreatable() -// $probe = new CircleProbe(); -// $probe->includeSystemCircles() -// ->mustBeMember(); -// -// $circle = $this->circleService->getCircle($circleId, $probe); - // get valid SyncedItem based on appId, itemType, itemId $syncedItem = $this->federatedSyncItemService->initSyncedItem( $this->originAppId, $this->originItemType, - $itemId, - true + $itemId ); $this->debugService->info( @@ -169,8 +164,13 @@ public function createShare( ] ); + $federatedUser = $this->federatedUserService->getCurrentEntity(); + if (!$federatedUser->isLocal()) { + throw new FederatedUserNotFoundException('unknown local user'); + } + $this->federatedSyncShareService->requestSyncedShareCreation( - $this->federatedUserService->getCurrentEntity(), + $federatedUser, $syncedItem, $circleId, $extraData @@ -257,7 +257,7 @@ public function updateItem( ); $this->debugService->info( - 'initiating the process of updating {syncedItem.singleId}', + 'initiating the process of updating SyncedItem {syncedItem.singleId}', '', [ 'itemId' => $itemId, 'syncedItem' => $syncedItem, @@ -266,8 +266,13 @@ public function updateItem( ] ); + $federatedUser = $this->federatedUserService->getCurrentEntity(); + if (!$federatedUser->isLocal()) { + throw new FederatedUserNotFoundException('unknown local user'); + } + $this->federatedSyncItemService->requestSyncedItemUpdate( - $this->federatedUserService->getCurrentEntity(), + $federatedUser, $syncedItem, new SyncedItemLock($updateType, $updateTypeId, $sumCheck), $extraData diff --git a/lib/Service/DebugService.php b/lib/Service/DebugService.php index a8a88ba2a..c8972da66 100644 --- a/lib/Service/DebugService.php +++ b/lib/Service/DebugService.php @@ -115,7 +115,7 @@ public function getSince(int $lastId): array { /** * @param string $action * @param string $circleId - * @param array $objects + * @param array $objects */ public function info(string $action, string $circleId = '', array $objects = []): void { if (!$this->isDebugEnabled()) { diff --git a/lib/Service/FederatedSyncItemService.php b/lib/Service/FederatedSyncItemService.php index 7bf81fab8..ef38263fc 100644 --- a/lib/Service/FederatedSyncItemService.php +++ b/lib/Service/FederatedSyncItemService.php @@ -244,9 +244,10 @@ public function initSyncedItem( throw new FederatedSyncConflictException("SyncedItem $appId.$itemType.$itemId is deprecated"); } - $this->debugService->info('Found SyncedItem {syncedItem.singleId} in database', '', [ - 'syncedItem' => $syncedItem - ]); + $this->debugService->info( + 'Found SyncedItem {syncedItem.singleId} in database', '', + ['syncedItem' => $syncedItem] + ); return $syncedItem; } catch (SyncedItemNotFoundException $e) { @@ -254,7 +255,7 @@ public function initSyncedItem( $syncManager = $this->federatedSyncService->getSyncManager($appId, $itemType); $this->debugService->info( - 'SyncedItem is unknown, calling {`serializeItem()} on {syncManager.class} to confirm item {itemId} is local', + 'SyncedItem is not known, calling {`itemExists()} on {syncManager.class} to confirm item {itemId} exists and is local', '', [ 'syncManager' => get_class($syncManager), @@ -263,9 +264,7 @@ public function initSyncedItem( ); if (!$syncManager->itemExists($itemId)) { - throw new FederatedSyncConflictException( - 'SyncedItem not found in database and does not appears to be local' - ); + throw new FederatedSyncConflictException('SyncedItem item does not exist'); } // create entry @@ -309,15 +308,21 @@ public function requestSyncedItemUpdate( $extraData, $remoteSum ); - - return; } else if (is_null($remoteSum)) { // this means that the request is not coming from remote location $this->requestSyncedItemUpdateRemote($federatedUser, $syncedItem, $syncedLock, $extraData); - - return; + } else { + throw new FederatedSyncConflictException('conflict in federatedSync'); } - throw new FederatedSyncConflictException(); + $this->debugService->info( + 'requested update on SyncedItem {syncedItem.singleId} is over. handing over the process', '', + [ + 'federatedUser' => $federatedUser, + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock, + 'extraData' => $extraData + ] + ); } @@ -347,21 +352,32 @@ private function requestSyncedItemUpdateLocal( array $extraData = [], ?string $remoteSum = null ): void { + $this->debugService->info( + 'SyncedItem is local, checking SyncedItemLock', '', + [ + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock, + 'remoteSum' => $remoteSum + ] + ); + + + // TODO: check $federatedUser is in one of the Circle the item is shared to. + // item will be lock during the process, only to be unlocked when new item checksum have // been calculated (on async process) $this->manageLock($syncedItem, $syncedLock, $remoteSum); + // TODO: manage exceptions to clear Lock on fail + if (!$this->isItemModifiable($federatedUser, $syncedItem, $syncedLock, $extraData)) { throw new FederatedSyncPermissionException('item modification not allowed'); } - $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); -// $syncManager->syncItem( -// $syncedItem->getItemId(), -// $item -// ); + // try to async in case process is configured as splittable $this->asyncService->splitArray(['success' => true]); + $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); $syncManager->onItemModification( $syncedItem->getItemId(), $syncedLock->getUpdateType(), @@ -370,8 +386,7 @@ private function requestSyncedItemUpdateLocal( $federatedUser ); - // this should split the process and give back hand if request is coming from a remote instance - + // initiate full async process if still on main thread $this->asyncService->asyncInternal( AsyncItemUpdate::class, new ReferencedDataStore( @@ -384,12 +399,36 @@ private function requestSyncedItemUpdateLocal( } + /** + * @param IFederatedUser $federatedUser + * @param SyncedItem $syncedItem + * @param SyncedItemLock $syncedLock + * @param array $extraData + * + * @throws FederatedItemException + * @throws FederatedSyncManagerNotFoundException + * @throws FederatedSyncRequestException + * @throws RemoteInstanceException + * @throws RemoteNotFoundException + * @throws RemoteResourceNotFoundException + * @throws UnknownRemoteException + */ private function requestSyncedItemUpdateRemote( IFederatedUser $federatedUser, SyncedItem $syncedItem, SyncedItemLock $syncedLock, array $extraData = [] ): void { + $this->debugService->info( + 'SyncedItem is not local, requesting remote instance {syncedItem.instance}', '', + [ + 'federatedUser' => $federatedUser, + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock, + 'extraData' => $extraData + ] + ); + $wrapper = new SyncedWrapper($federatedUser, $syncedItem, $syncedLock, null, $extraData); $this->interfaceService->setCurrentInterfaceFromInstance($syncedItem->getInstance()); $data = $this->remoteStreamService->resultRequestRemoteInstance( @@ -400,10 +439,21 @@ private function requestSyncedItemUpdateRemote( ); if (!$this->getBool('success', $data)) { - throw new FederatedSyncRequestException(); + throw new FederatedSyncRequestException('status is ok, but action was not a success'); } $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); + + $this->debugService->info( + 'calling {`onItemModification()} on {syncManager.class} to update local entry', '', + [ + 'federatedUser' => $federatedUser, + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock, + 'extraData' => $extraData + ] + ); + $syncManager->onItemModification( $syncedItem->getItemId(), $syncedLock->getUpdateType(), @@ -411,15 +461,6 @@ private function requestSyncedItemUpdateRemote( $extraData, $federatedUser ); - -// $syncManager->syncItem( -// $syncedItem->getItemId(), -// $data -// ); - - // update item based on current (old) checksum to confirm item was not already updated (race condition) - // do not update checksum -// $this->updateChecksum($syncedItem->getSingleId(), $data); } @@ -462,18 +503,21 @@ private function createSyncedItem(string $appId, string $itemType, string $itemI ['syncedItem' => $syncedItem] ); -// try { -// $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); -// } catch (SyncedItemNotFoundException $e) { $this->debugService->info( 'storing SyncedItem {syncedItem.singleId} in database', '', ['syncedItem' => $syncedItem] ); - $this->syncedItemRequest->save($syncedItem); - -// } - + try { + $this->syncedItemRequest->save($syncedItem); + } catch (UniqueConstraintViolationException $e) { + // in case of race condition + $syncedItem = $this->syncedItemRequest->getSyncedItem( + $syncedItem->getAppId(), + $syncedItem->getItemType(), + $syncedItem->getItemId() + ); + } return $syncedItem; } @@ -577,7 +621,6 @@ private function isItemModifiable( SyncedItemLock $syncedLock, array $extraData = [] ): bool { -// $federatedUser $syncManager = $this->federatedSyncService->initSyncManager($syncedItem); $this->debugService->info( 'sharing of SyncedItem {syncedItem.singleId} looks doable, calling {`isShareCreatable()} on {syncManager.class} for confirmation', @@ -712,6 +755,17 @@ private function manageLock( try { $this->syncedItemLockRequest->clean(self::LOCK_TIMEOUT); $this->syncedItemLockRequest->getSyncedItemLock($syncedLock); + $this->debugService->info( + 'SyncedItem {syncedLock.singleId} is locked. waiting a second and try again', '', + [ + 'loop' => $i, + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock, + 'remoteSum' => $remoteSum, + 'lastTry' => $lastTry + ] + ); + sleep(1); } catch (SyncedItemNotFoundException $e) { $locked = false; @@ -724,17 +778,40 @@ private function manageLock( } if (!is_null($remoteSum) && $syncedLock->isVerifyChecksum()) { + $this->debugService->info( + 'Action require up-to-date checksum {remoteSum} from remote instance to update SyncedItem {syncedItem.singleId}', + '', + [ + 'remoteSum' => $remoteSum, + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock + ] + ); $known = $this->syncedItemRequest->getSyncedItemFromSingleId($syncedItem->getSingleId()); if ($known->getChecksum() !== $remoteSum) { throw new SyncedItemLockException('checksum is too old, sync required'); } } + $this->debugService->info( + 'SyncedItem {syncedLock.singleId} is not locked', '', + [ + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock + ] + ); + try { $this->syncedItemLockRequest->save($syncedLock); } catch (UniqueConstraintViolationException $e) { - // in case of race condition between the check of lock and the save of a new one. if (!$lastTry) { + $this->debugService->info( + 'Race condition during the generation of the lock, going back to previous step', '', + [ + 'syncedItem' => $syncedItem, + 'syncedLock' => $syncedLock + ] + ); $this->manageLock($syncedItem, $syncedLock, $remoteSum, true); } else { throw new SyncedItemLockException('too many request at the same time, try again later');