This repository has been archived by the owner on Nov 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Mapping.kt
125 lines (113 loc) · 3.77 KB
/
Mapping.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.mkring.james.mapping
import com.mkring.james.Chat
import com.mkring.james.JamesPool
import com.mkring.james.chatbackend.OutgoingPayload
import com.mkring.james.chatbackend.UniqueChatTarget
import com.mkring.james.lg
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import java.util.concurrent.TimeUnit
import kotlin.coroutines.CoroutineContext
data class MappingPattern(val pattern: String, val info: String)
/**
* use map dsl function inside james
*/
class Mapping internal constructor(
private val commandText: String,
/**
* uniq chat identifier; content depends on the used backend
*/
val uniqueChatTarget: UniqueChatTarget,
/**
* if available the username will be provided
*/
val username: String?,
private val mappingPrefix: String,
private val parentChat: Chat
) : CoroutineScope {
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + JamesPool
/**
* pattern will be present too, but not james name!
*
* james test arg1 arg2 -> [test,arg1,arg2]
* test arg1 arg2 -> [test,arg1,arg2]
*/
val arguments by lazy {
lg("commandText=$commandText username=$username")
commandText.removePrefix(mappingPrefix).trim().split(Regex("\\s+")).filterNot { it.isEmpty() }.toList()
}
/**
* default timeout when asking
*/
var askTimeout = 120
/**
* default timeout timeunit when asking
*/
var timeUnit = TimeUnit.SECONDS
/**
* If you ask with retries, this will be printed when the predicate is false
*/
var wrongAnswerText = "incompatible answer!"
/**
* If you ask with retries, this will be printed when a timeout happens
*/
var timeoutText = "timeout!"
/**
* If you ask with retries and all failed, this will be printed
*/
var askWithRetryFailedText = "well, nevermind then"
/**
* Send some text to the chat counterpart
*/
fun send(text: String, options: Map<String, String> = emptyMap()) {
parentChat.send(OutgoingPayload(uniqueChatTarget, text, options))
}
/**
* Ask something using the mapping timeout
* @param text the quesion to be asked
* @param options chat specific options -> see James README
*/
fun ask(text: String, options: Map<String, String> = emptyMap()): Ask<String> =
parentChat.ask(text, options, askTimeout, timeUnit, uniqueChatTarget)
/**
* Ask something and retry X times if timeout OR [predicate] false
* @param retries number of [retries] after the first failure. retries = 2 will ask a total of 3
* @param predicate this will determine if the answer is valid
* @param text the question to be asked
* @param options chat specific options -> see James README
*/
fun askWithRetry(
retries: Int, text: String, options: Map<String, String> = emptyMap(),
predicate: (String) -> Boolean
): Ask<String> {
//sequence is lazy eval!
val firstOrNull = IntRange(0, retries).asSequence().map {
ask(text, options)
}.filter {
when (it) {
is Ask.Timeout -> {
send(timeoutText)
false
}
is Ask.Answer -> {
when (predicate(it.value)) {
true -> true
else -> {
send(wrongAnswerText)
false
}
}
}
}
}.firstOrNull()
return when (firstOrNull) {
null -> {
send(askWithRetryFailedText)
Ask.Timeout
}
else -> firstOrNull
}
}
}