Skip to content

Commit ac48054

Browse files
committed
refactor(model-client): addressed a load of detekt issues
1 parent 4128f49 commit ac48054

2 files changed

Lines changed: 135 additions & 17 deletions

File tree

model-client/src/commonMain/kotlin/org/modelix/model/client2/ReplicatedModel.kt

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,12 @@ import org.modelix.model.mutable.asModel
5858
* Dispose should be called on this, as otherwise a regular polling will go on.
5959
*
6060
* @property client the model client to connect to the model server
61-
* @property branchRef branch or repository reference
62-
* @property providedScope the CoroutineScope to use for the suspendable tasks
63-
* @property initialRemoteVersion the last version on the server from which we want to start the synchronization
61+
* @param branchRefOrNull branch reference, null if strictly version-based
62+
* @property idGenerator the generator for node IDs
63+
* @param providedScope the CoroutineScope to use for the suspendable tasks
64+
* @param initialRemoteVersion the last version on the server from which we want to start the synchronization
65+
* @param repositoryId the repository ID, required if [versionHash] is provided
66+
* @param versionHash the version hash to replicate, if not using a branch reference
6467
*/
6568
class ReplicatedModel(
6669
val client: IModelClientV2,
@@ -80,7 +83,7 @@ class ReplicatedModel(
8083
initialRemoteVersion: CLVersion? = null,
8184
) : this(client, branchRef, idGenerator, providedScope, initialRemoteVersion, null, null)
8285

83-
val branchRef: BranchReference get() = branchRefOrNull ?: throw IllegalStateException("ReplicatedModel is in read-only version mode")
86+
val branchRef: BranchReference get() = branchRefOrNull ?: error("ReplicatedModel is in read-only version mode")
8487

8588
private val scope = providedScope ?: CoroutineScope(Dispatchers.Default)
8689
private var state = State.New
@@ -98,24 +101,33 @@ class ReplicatedModel(
98101
if (branchRefOrNull != null) {
99102
check(versionHash == null) { "Cannot provide both branchRef and versionHash" }
100103
remoteVersion = RemoteVersionFromBranch(client, branchRefOrNull, initialRemoteVersion)
101-
} else if (versionHash != null) {
102-
val repoId = repositoryId ?: throw IllegalArgumentException("repositoryId is required when versionHash is provided")
103-
remoteVersion = RemoteVersionFromHash(client, repoId, versionHash)
104104
} else {
105-
throw IllegalArgumentException("Either branchRef or versionHash must be provided")
105+
require(versionHash != null) { "Either branchRef or versionHash must be provided" }
106+
require(repositoryId != null) { "repositoryId is required when versionHash is provided" }
107+
remoteVersion = RemoteVersionFromHash(client, repositoryId, versionHash)
106108
}
107109
}
108110

109111
private fun getLocalModel(): LocalModel = checkNotNull(localModel) { "Model is not initialized yet" }
110112

113+
/**
114+
* Returns the model as an [IMutableModel].
115+
*/
111116
fun getModel(): IMutableModel {
112117
return getLocalModel().versionedModelTree.asModel()
113118
}
114119

120+
/**
121+
* Returns the underlying [VersionedModelTree].
122+
*/
115123
fun getVersionedModelTree(): IMutableModelTree = getLocalModel().versionedModelTree
116124

125+
/**
126+
* Starts the synchronization process.
127+
* Use [dispose] to stop it.
128+
*/
117129
suspend fun start(): IMutableModelTree {
118-
if (state != State.New) throw IllegalStateException("already started")
130+
check(state == State.New) { "already started" }
119131
state = State.Starting
120132

121133
if (localModel == null) {
@@ -137,7 +149,7 @@ class ReplicatedModel(
137149
throw ex
138150
} catch (ex: Throwable) {
139151
LOG.error(ex) { "Failed polling" }
140-
nextDelayMs = (nextDelayMs * 3 / 2).coerceIn(1000, 30000)
152+
nextDelayMs = (nextDelayMs * 3 / 2).coerceIn(POLLING_MIN_DELAY, POLLING_MAX_DELAY)
141153
}
142154
}
143155
}
@@ -160,18 +172,23 @@ class ReplicatedModel(
160172
return getVersionedModelTree()
161173
}
162174

175+
/**
176+
* Resets the local model to the latest version on the server.
177+
*/
163178
suspend fun resetToServerVersion() {
164179
// This delegates to remoteVersion which handles pull/load
165180
val version = remoteVersion.getInitialVersion()
166181
getLocalModel().resetToVersion(version)
167182
}
168183

184+
/**
185+
* Returns true if this [ReplicatedModel] has been disposed.
186+
*/
169187
fun isDisposed(): Boolean = state == State.Disposed
170188

171-
private fun checkDisposed() {
172-
if (state == State.Disposed) throw IllegalStateException("disposed")
173-
}
174-
189+
/**
190+
* Stops the synchronization and releases resources.
191+
*/
175192
fun dispose() {
176193
if (state == State.Disposed) return
177194
pollingJob?.cancel("disposed")
@@ -208,16 +225,19 @@ class ReplicatedModel(
208225
private suspend fun pushLocalChanges() {
209226
if (isDisposed()) return
210227

211-
for (attempt in 1..10) {
228+
repeat(PUSH_MAX_ATTEMPTS) {
212229
val version = getLocalModel().createNewLocalVersion() ?: getLocalModel().getCurrentVersion()
213230
val received = remoteVersion.push(version)
214231
if (received.getContentHash() == version.getContentHash()) return
215232
remoteVersionReceived(received, version)
216233
}
217234

218-
throw IllegalStateException("Failed to push local changes after 10 attempts")
235+
error("Failed to push local changes after $PUSH_MAX_ATTEMPTS attempts")
219236
}
220237

238+
/**
239+
* Returns the current version of the local model.
240+
*/
221241
fun getCurrentVersion(): CLVersion {
222242
return getLocalModel().getCurrentVersion()
223243
}
@@ -231,13 +251,22 @@ class ReplicatedModel(
231251

232252
companion object {
233253
private val LOG = KotlinLogging.logger { }
254+
private const val POLLING_MIN_DELAY = 1000L
255+
private const val POLLING_MAX_DELAY = 30000L
256+
private const val PUSH_MAX_ATTEMPTS = 10
234257
}
235258
}
236259

260+
/**
261+
* Creates a [ReplicatedModel] for the given branch.
262+
*/
237263
fun IModelClientV2.getReplicatedModel(branchRef: BranchReference, idGenerator: (TreeId) -> INodeIdGenerator<INodeReference>): ReplicatedModel {
238264
return ReplicatedModel(this, branchRef, idGenerator)
239265
}
240266

267+
/**
268+
* Creates a [ReplicatedModel] for the given branch with a provided scope.
269+
*/
241270
fun IModelClientV2.getReplicatedModel(branchRef: BranchReference, idGenerator: (TreeId) -> INodeIdGenerator<INodeReference>, scope: CoroutineScope): ReplicatedModel {
242271
return ReplicatedModel(this, branchRef, idGenerator, scope)
243272
}

model-client/src/jsMain/kotlin/org/modelix/model/client2/ClientJS.kt

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ fun loadModelsFromJsonAsBranch(json: Array<String>): MutableModelTreeJs {
7070
*
7171
* @param url URL to the V2 endpoint of the model server.
7272
* e.g., http://localhost:28102/v2
73+
* @param bearerTokenProvider provider for the bearer token
7374
*/
7475
@JsExport
7576
fun connectClient(url: String, bearerTokenProvider: (() -> Promise<String?>)? = null): Promise<ClientJS> {
@@ -86,13 +87,30 @@ fun connectClient(url: String, bearerTokenProvider: (() -> Promise<String?>)? =
8687
}
8788
}
8889

90+
/**
91+
* ID generation scheme for the JS client.
92+
*/
8993
@JsExport
90-
sealed class IdSchemeJS() {
94+
sealed class IdSchemeJS {
95+
/**
96+
* MPS ID generation scheme.
97+
*/
9198
object MPS : IdSchemeJS()
99+
100+
/**
101+
* Modelix ID generation scheme.
102+
*/
92103
object MODELIX : IdSchemeJS()
104+
105+
/**
106+
* Read-only ID generation scheme.
107+
*/
93108
object READONLY : IdSchemeJS()
94109
}
95110

111+
/**
112+
* Combines version information with a model tree.
113+
*/
96114
@JsExport
97115
data class VersionInformationWithModelTree(val version: VersionInformationJS, val tree: MutableModelTreeJs)
98116

@@ -127,20 +145,73 @@ interface ClientJS {
127145
*/
128146
fun initRepository(repositoryId: String, useRoleIds: Boolean = true): Promise<Unit>
129147

148+
/**
149+
* Loads a specific version of the model in read-only mode.
150+
*
151+
* @param repositoryId ID of the repository.
152+
* @param versionHash Hash of the version to load.
153+
* @return A promise resolving to the version information and tree.
154+
*/
130155
fun loadReadonlyVersion(repositoryId: String, versionHash: String): Promise<VersionInformationWithModelTree>
131156

157+
/**
158+
* Retrieves a range of version history.
159+
*/
132160
fun getHistoryRange(repositoryId: String, headVersion: String, skip: Int, limit: Int): Promise<Array<VersionInformationJS>>
161+
162+
/**
163+
* Retrieves history sessions.
164+
*/
133165
fun getHistorySessions(repositoryId: String, headVersion: String, delaySeconds: Int, skip: Int, limit: Int): Promise<Array<HistoryIntervalJS>>
166+
167+
/**
168+
* Retrieves history for fixed intervals.
169+
*/
134170
fun getHistoryForFixedIntervals(repositoryId: String, headVersion: String, intervalDurationSeconds: Int, skip: Int, limit: Int): Promise<Array<HistoryIntervalJS>>
171+
172+
/**
173+
* Retrieves history for provided intervals.
174+
*/
135175
fun getHistoryForProvidedIntervals(repositoryId: String, headVersion: String, splitAt: Array<Date>): Promise<Array<HistoryIntervalJS>>
136176

177+
/**
178+
* Retrieves history range for a branch.
179+
*/
137180
fun getHistoryRangeForBranch(repositoryId: String, branchId: String, skip: Int, limit: Int): Promise<Array<VersionInformationJS>>
181+
182+
/**
183+
* Retrieves history sessions for a branch.
184+
*/
138185
fun getHistorySessionsForBranch(repositoryId: String, branchId: String, delaySeconds: Int, skip: Int, limit: Int): Promise<Array<HistoryIntervalJS>>
186+
187+
/**
188+
* Retrieves history for fixed intervals for a branch.
189+
*/
139190
fun getHistoryForFixedIntervalsForBranch(repositoryId: String, branchId: String, intervalDurationSeconds: Int, skip: Int, limit: Int): Promise<Array<HistoryIntervalJS>>
191+
192+
/**
193+
* Retrieves history for provided intervals for a branch.
194+
*/
140195
fun getHistoryForProvidedIntervalsForBranch(repositoryId: String, branchId: String, splitAt: Array<Date>): Promise<Array<HistoryIntervalJS>>
141196

197+
/**
198+
* Reverts the branch to a specific version.
199+
*
200+
* @param repositoryId ID of the repository.
201+
* @param branchId ID of the branch.
202+
* @param targetVersionHash Hash of the version to revert to.
203+
* @return A promise resolving to the new version hash.
204+
*/
142205
fun revertTo(repositoryId: String, branchId: String, targetVersionHash: String): Promise<String>
143206

207+
/**
208+
* Computes the difference between two versions as mutation parameters.
209+
*
210+
* @param repositoryId ID of the repository.
211+
* @param newVersion Hash of the new version.
212+
* @param oldVersion Hash of the old version.
213+
* @return A promise resolving to an array of mutation parameters.
214+
*/
144215
fun diffAsMutationParameters(repositoryId: String, newVersion: String, oldVersion: String): Promise<Array<MutationParametersJS>>
145216

146217
/**
@@ -195,9 +266,15 @@ interface ClientJS {
195266
*
196267
* @param repositoryId Repository ID of the branch to replicate.
197268
* @param branchId ID of the branch to replicate.
269+
* @param idScheme The ID scheme to use for generating node IDs.
198270
*/
199271
fun startReplicatedModel(repositoryId: String, branchId: String, idScheme: IdSchemeJS): Promise<ReplicatedModelJS>
200272

273+
/**
274+
* Starts replicated models for the given parameters.
275+
*
276+
* @param parameters configuration for the replicated models
277+
*/
201278
fun startReplicatedModels(parameters: Array<ReplicatedModelParameters>): Promise<ReplicatedModelJS>
202279

203280
/**
@@ -206,6 +283,15 @@ interface ClientJS {
206283
fun dispose()
207284
}
208285

286+
/**
287+
* Configuration for a replicated model.
288+
*
289+
* @property repositoryId The ID of the repository.
290+
* @property branchId The ID of the branch to replicate. Mutually exclusive with [versionHash].
291+
* @property idScheme The ID scheme to use.
292+
* @property readonly If true, the model will be read-only.
293+
* @property versionHash The hash of the version to load properties from. Mutually exclusive with [branchId].
294+
*/
209295
@JsExport
210296
data class ReplicatedModelParameters(
211297
val repositoryId: String,
@@ -476,6 +562,9 @@ interface MutableModelTreeJs {
476562
*/
477563
val rootNode: INodeJS
478564

565+
/**
566+
* Get all root nodes in the branch.
567+
*/
479568
fun getRootNodes(): Array<INodeJS>
480569

481570
/**

0 commit comments

Comments
 (0)