Skip to content

Commit e6c1300

Browse files
authored
PIR: Add support for Condition css action (#6993)
Task/Issue URL: https://app.asana.com/1/137249556945/project/1201462763415876/task/1210822764373104?focus=true ### Description See attached task descrtiption. ### Steps to test this PR Testing should be done on the stacked PRs.
1 parent 9617eca commit e6c1300

File tree

12 files changed

+1202
-89
lines changed

12 files changed

+1202
-89
lines changed

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/common/BrokerStepsParser.kt

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@ import com.duckduckgo.pir.impl.store.PirRepository
2929
import com.squareup.anvil.annotations.ContributesBinding
3030
import com.squareup.moshi.JsonAdapter
3131
import com.squareup.moshi.Moshi
32-
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
33-
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
3432
import kotlinx.coroutines.withContext
3533
import logcat.LogPriority.ERROR
3634
import logcat.logcat
3735
import javax.inject.Inject
36+
import javax.inject.Named
3837

3938
interface BrokerStepsParser {
4039
/**
@@ -97,28 +96,10 @@ interface BrokerStepsParser {
9796
class RealBrokerStepsParser @Inject constructor(
9897
private val dispatcherProvider: DispatcherProvider,
9998
private val repository: PirRepository,
99+
@Named("pir") private val moshi: Moshi,
100100
) : BrokerStepsParser {
101101
val adapter: JsonAdapter<BrokerStep> by lazy {
102-
Moshi.Builder()
103-
.add(
104-
PolymorphicJsonAdapterFactory.of(BrokerAction::class.java, "actionType")
105-
.withSubtype(BrokerAction.Extract::class.java, "extract")
106-
.withSubtype(BrokerAction.Expectation::class.java, "expectation")
107-
.withSubtype(BrokerAction.Click::class.java, "click")
108-
.withSubtype(BrokerAction.FillForm::class.java, "fillForm")
109-
.withSubtype(BrokerAction.Navigate::class.java, "navigate")
110-
.withSubtype(BrokerAction.GetCaptchaInfo::class.java, "getCaptchaInfo")
111-
.withSubtype(BrokerAction.SolveCaptcha::class.java, "solveCaptcha")
112-
.withSubtype(BrokerAction.EmailConfirmation::class.java, "emailConfirmation"),
113-
)
114-
.add(
115-
PolymorphicJsonAdapterFactory.of(BrokerStep::class.java, "stepType")
116-
.withSubtype(ScanStep::class.java, "scan")
117-
.withSubtype(OptOutStep::class.java, "optOut"),
118-
)
119-
.add(KotlinJsonAdapterFactory())
120-
.build()
121-
.adapter(BrokerStep::class.java)
102+
moshi.adapter(BrokerStep::class.java)
122103
}
123104

124105
override suspend fun parseStep(

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/common/PirRunStateHandler.kt

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,7 @@ import com.duckduckgo.pir.impl.models.ExtractedProfile
3838
import com.duckduckgo.pir.impl.pixels.PirPixelSender
3939
import com.duckduckgo.pir.impl.scheduling.JobRecordUpdater
4040
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse
41-
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ClickResponse
42-
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ExpectationResponse
4341
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ExtractedResponse
44-
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.FillFormResponse
45-
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.GetCaptchaInfoResponse
46-
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.NavigateResponse
47-
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.SolveCaptchaResponse
4842
import com.duckduckgo.pir.impl.store.PirEventsRepository
4943
import com.duckduckgo.pir.impl.store.PirRepository
5044
import com.duckduckgo.pir.impl.store.PirSchedulingRepository
@@ -56,10 +50,9 @@ import com.duckduckgo.pir.impl.store.db.EmailConfirmationEventType.EMAIL_CONFIRM
5650
import com.duckduckgo.pir.impl.store.db.PirBrokerScanLog
5751
import com.squareup.anvil.annotations.ContributesBinding
5852
import com.squareup.moshi.Moshi
59-
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
60-
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
6153
import kotlinx.coroutines.withContext
6254
import javax.inject.Inject
55+
import javax.inject.Named
6356

6457
interface PirRunStateHandler {
6558
suspend fun handleState(pirRunState: PirRunState)
@@ -170,24 +163,8 @@ class RealPirRunStateHandler @Inject constructor(
170163
private val jobRecordUpdater: JobRecordUpdater,
171164
private val pirSchedulingRepository: PirSchedulingRepository,
172165
private val currentTimeProvider: CurrentTimeProvider,
166+
@Named("pir") private val moshi: Moshi,
173167
) : PirRunStateHandler {
174-
private val moshi: Moshi by lazy {
175-
Moshi
176-
.Builder()
177-
.add(
178-
PolymorphicJsonAdapterFactory
179-
.of(PirSuccessResponse::class.java, "actionType")
180-
.withSubtype(NavigateResponse::class.java, "navigate")
181-
.withSubtype(ExtractedResponse::class.java, "extract")
182-
.withSubtype(GetCaptchaInfoResponse::class.java, "getCaptchaInfo")
183-
.withSubtype(SolveCaptchaResponse::class.java, "solveCaptcha")
184-
.withSubtype(ClickResponse::class.java, "click")
185-
.withSubtype(ExpectationResponse::class.java, "expectation")
186-
.withSubtype(FillFormResponse::class.java, "fillForm"),
187-
).add(KotlinJsonAdapterFactory())
188-
.build()
189-
}
190-
191168
private val pirSuccessAdapter by lazy { moshi.adapter(PirSuccessResponse::class.java) }
192169

193170
override suspend fun handleState(pirRunState: PirRunState) =
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2025 DuckDuckGo
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.duckduckgo.pir.impl.common.actions
18+
19+
import com.duckduckgo.di.scopes.AppScope
20+
import com.duckduckgo.pir.impl.common.BrokerStepsParser.BrokerStep
21+
import com.duckduckgo.pir.impl.common.actions.EventHandler.Next
22+
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.Event
23+
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.Event.ConditionExpectationSucceeded
24+
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.Event.ExecuteBrokerStepAction
25+
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.State
26+
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData.UserProfile
27+
import com.squareup.anvil.annotations.ContributesMultibinding
28+
import javax.inject.Inject
29+
import kotlin.reflect.KClass
30+
31+
@ContributesMultibinding(
32+
scope = AppScope::class,
33+
boundType = EventHandler::class,
34+
)
35+
class ConditionExpectationSucceededEventHandler @Inject constructor() : EventHandler {
36+
override val event: KClass<out Event> = ConditionExpectationSucceeded::class
37+
38+
override suspend fun invoke(
39+
state: State,
40+
event: Event,
41+
): Next {
42+
val actionsToAppend = (event as ConditionExpectationSucceeded).conditionActions
43+
val currentBrokerStep = state.brokerStepsToExecute[state.currentBrokerStepIndex]
44+
45+
val updatedBrokerSteps = state.brokerStepsToExecute.toMutableList()
46+
val updatedBrokerActions = currentBrokerStep.actions.toMutableList().apply {
47+
this.addAll(
48+
state.currentActionIndex + 1,
49+
actionsToAppend,
50+
)
51+
}
52+
val updatedBrokerStep = when (currentBrokerStep) {
53+
is BrokerStep.ScanStep -> currentBrokerStep.copy(actions = updatedBrokerActions)
54+
is BrokerStep.OptOutStep -> currentBrokerStep.copy(actions = updatedBrokerActions)
55+
is BrokerStep.EmailConfirmationStep -> currentBrokerStep.copy(actions = updatedBrokerActions)
56+
}
57+
58+
updatedBrokerSteps[state.currentBrokerStepIndex] = updatedBrokerStep
59+
60+
return Next(
61+
nextState = state.copy(
62+
currentActionIndex = state.currentActionIndex + 1,
63+
brokerStepsToExecute = updatedBrokerSteps,
64+
),
65+
nextEvent = ExecuteBrokerStepAction(
66+
UserProfile(
67+
userProfile = state.profileQuery,
68+
),
69+
),
70+
)
71+
}
72+
}

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/common/actions/JsActionSuccessEventHandler.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import com.duckduckgo.pir.impl.common.PirRunStateHandler.PirRunState.BrokerOptOu
2525
import com.duckduckgo.pir.impl.common.PirRunStateHandler.PirRunState.BrokerScanActionSucceeded
2626
import com.duckduckgo.pir.impl.common.actions.EventHandler.Next
2727
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.Event
28+
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.Event.ConditionExpectationSucceeded
2829
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.Event.ExecuteBrokerStepAction
2930
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.Event.JsActionSuccess
3031
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.SideEffect.EvaluateJs
@@ -33,6 +34,7 @@ import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.SideEf
3334
import com.duckduckgo.pir.impl.common.actions.PirActionsRunnerStateEngine.State
3435
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData.UserProfile
3536
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ClickResponse
37+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ConditionResponse
3638
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ExpectationResponse
3739
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ExtractedResponse
3840
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.FillFormResponse
@@ -151,6 +153,28 @@ class JsActionSuccessEventHandler @Inject constructor(
151153
),
152154
)
153155
}
156+
157+
is ConditionResponse -> {
158+
if (pirSuccessResponse.response.actions.isNotEmpty()) {
159+
Next(
160+
nextState = baseSuccessState,
161+
nextEvent = ConditionExpectationSucceeded(
162+
pirSuccessResponse.response.actions,
163+
),
164+
)
165+
} else {
166+
Next(
167+
nextState = baseSuccessState.copy(
168+
currentActionIndex = baseSuccessState.currentActionIndex + 1,
169+
),
170+
nextEvent = ExecuteBrokerStepAction(
171+
UserProfile(
172+
userProfile = baseSuccessState.profileQuery,
173+
),
174+
),
175+
)
176+
}
177+
}
154178
}
155179
}
156180
}

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/common/actions/PirActionsRunnerStateEngine.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ interface PirActionsRunnerStateEngine {
122122
val actionId: String,
123123
val responseData: ResponseData?,
124124
) : Event()
125+
126+
data class ConditionExpectationSucceeded(
127+
val conditionActions: List<BrokerAction>,
128+
) : Event()
125129
}
126130

127131
/**

pir/pir-impl/src/main/java/com/duckduckgo/pir/impl/di/PirModule.kt

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import com.duckduckgo.common.utils.DispatcherProvider
2424
import com.duckduckgo.common.utils.plugins.PluginPoint
2525
import com.duckduckgo.data.store.api.SharedPreferencesProvider
2626
import com.duckduckgo.di.scopes.AppScope
27+
import com.duckduckgo.pir.impl.common.BrokerStepsParser.BrokerStep
28+
import com.duckduckgo.pir.impl.common.BrokerStepsParser.BrokerStep.OptOutStep
29+
import com.duckduckgo.pir.impl.common.BrokerStepsParser.BrokerStep.ScanStep
2730
import com.duckduckgo.pir.impl.common.CaptchaResolver
2831
import com.duckduckgo.pir.impl.common.NativeBrokerActionHandler
2932
import com.duckduckgo.pir.impl.common.RealNativeBrokerActionHandler
@@ -33,6 +36,19 @@ import com.duckduckgo.pir.impl.common.actions.RealPirActionsRunnerStateEngineFac
3336
import com.duckduckgo.pir.impl.scripts.BrokerActionProcessor
3437
import com.duckduckgo.pir.impl.scripts.PirMessagingInterface
3538
import com.duckduckgo.pir.impl.scripts.RealBrokerActionProcessor
39+
import com.duckduckgo.pir.impl.scripts.models.BrokerAction
40+
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData
41+
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData.SolveCaptcha
42+
import com.duckduckgo.pir.impl.scripts.models.PirScriptRequestData.UserProfile
43+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse
44+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ClickResponse
45+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ConditionResponse
46+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ExpectationResponse
47+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.ExtractedResponse
48+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.FillFormResponse
49+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.GetCaptchaInfoResponse
50+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.NavigateResponse
51+
import com.duckduckgo.pir.impl.scripts.models.PirSuccessResponse.SolveCaptchaResponse
3652
import com.duckduckgo.pir.impl.service.DbpService
3753
import com.duckduckgo.pir.impl.store.PirDatabase
3854
import com.duckduckgo.pir.impl.store.PirRepository
@@ -48,10 +64,14 @@ import com.duckduckgo.pir.impl.store.db.ScanLogDao
4864
import com.duckduckgo.pir.impl.store.db.ScanResultsDao
4965
import com.duckduckgo.pir.impl.store.db.UserProfileDao
5066
import com.squareup.anvil.annotations.ContributesTo
67+
import com.squareup.moshi.Moshi
68+
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
69+
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
5170
import dagger.Module
5271
import dagger.Provides
5372
import dagger.SingleInstanceIn
5473
import kotlinx.coroutines.CoroutineScope
74+
import javax.inject.Named
5575

5676
@Module
5777
@ContributesTo(AppScope::class)
@@ -145,9 +165,10 @@ class PirModule {
145165
@Provides
146166
fun providesBrokerActionProcessor(
147167
pirMessagingInterface: PirMessagingInterface,
168+
@Named("pir") moshi: Moshi,
148169
): BrokerActionProcessor {
149170
// Creates a new instance everytime is BrokerActionProcessor injected
150-
return RealBrokerActionProcessor(pirMessagingInterface)
171+
return RealBrokerActionProcessor(pirMessagingInterface, moshi)
151172
}
152173

153174
@Provides
@@ -176,4 +197,43 @@ class PirModule {
176197
coroutineScope,
177198
)
178199
}
200+
201+
@Provides
202+
@SingleInstanceIn(AppScope::class)
203+
@Named("pir")
204+
fun providePirMoshi(moshi: Moshi): Moshi {
205+
return moshi.newBuilder()
206+
.add(
207+
PolymorphicJsonAdapterFactory.of(PirScriptRequestData::class.java, "data")
208+
.withSubtype(SolveCaptcha::class.java, "solveCaptcha")
209+
.withSubtype(UserProfile::class.java, "userProfile"),
210+
).add(
211+
PolymorphicJsonAdapterFactory.of(BrokerAction::class.java, "actionType")
212+
.withSubtype(BrokerAction.Extract::class.java, "extract")
213+
.withSubtype(BrokerAction.Expectation::class.java, "expectation")
214+
.withSubtype(BrokerAction.Click::class.java, "click")
215+
.withSubtype(BrokerAction.FillForm::class.java, "fillForm")
216+
.withSubtype(BrokerAction.Navigate::class.java, "navigate")
217+
.withSubtype(BrokerAction.GetCaptchaInfo::class.java, "getCaptchaInfo")
218+
.withSubtype(BrokerAction.SolveCaptcha::class.java, "solveCaptcha")
219+
.withSubtype(BrokerAction.EmailConfirmation::class.java, "emailConfirmation")
220+
.withSubtype(BrokerAction.Condition::class.java, "condition"),
221+
).add(
222+
PolymorphicJsonAdapterFactory.of(BrokerStep::class.java, "stepType")
223+
.withSubtype(ScanStep::class.java, "scan")
224+
.withSubtype(OptOutStep::class.java, "optOut"),
225+
).add(
226+
PolymorphicJsonAdapterFactory.of(PirSuccessResponse::class.java, "actionType")
227+
.withSubtype(NavigateResponse::class.java, "navigate")
228+
.withSubtype(ExtractedResponse::class.java, "extract")
229+
.withSubtype(GetCaptchaInfoResponse::class.java, "getCaptchaInfo")
230+
.withSubtype(SolveCaptchaResponse::class.java, "solveCaptcha")
231+
.withSubtype(ClickResponse::class.java, "click")
232+
.withSubtype(ExpectationResponse::class.java, "expectation")
233+
.withSubtype(FillFormResponse::class.java, "fillForm")
234+
.withSubtype(ConditionResponse::class.java, "condition"),
235+
)
236+
.add(KotlinJsonAdapterFactory())
237+
.build()
238+
}
179239
}

0 commit comments

Comments
 (0)