Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,59 @@ package com.github.pushpavel.autocp.gather.base
import com.github.pushpavel.autocp.common.helpers.ioScope
import com.github.pushpavel.autocp.common.res.R
import com.github.pushpavel.autocp.gather.models.ProblemJson
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.ProjectActivity
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Job
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.Json
import java.net.SocketTimeoutException

/**
* Bridge between Competitive Companion extension and [BatchProcessor]
* Application-level service to ensure only one instance is running
*/
class ProblemGatheringBridge : ProjectActivity, DumbAware {
@Service(Service.Level.APP)
class ProblemGatheringBridge : Disposable {
private val scope = ioScope()
private val serializer = Json { ignoreUnknownKeys = true }

@Volatile
private var isRunning = false

@Volatile
private var serverJob: Job? = null

fun runActivity(project: Project) {
companion object {
fun getInstance(): ProblemGatheringBridge {
return ApplicationManager.getApplication().getService(ProblemGatheringBridge::class.java)
}
}

fun start() {
if (isRunning) {
return
}

isRunning = true

// initialize server
scope.launch {
serverJob = scope.launch {
try {
val serverSocket = openServerSocketAsync(
R.others.competitiveCompanionPorts
).await() ?: throw ProblemGatheringErr.AllPortsTakenErr(R.others.competitiveCompanionPorts)

serverSocket.use {
while (true) {
while (isActive) {
try {
coroutineScope {
val message = listenForMessageAsync(
Expand All @@ -51,12 +77,31 @@ class ProblemGatheringBridge : ProjectActivity, DumbAware {
} catch (e: ProblemGatheringErr) {
R.notify.problemGatheringErr(e)
} catch (e: Exception) {
R.notify.problemGatheringUncaught(e)
if (e !is CancellationException) {
R.notify.problemGatheringUncaught(e)
}
} finally {
isRunning = false
BatchProcessor.interruptBatch()
}
}
}

override suspend fun execute(project: Project) = runActivity(project)
fun stop() {
serverJob?.cancel()
isRunning = false
}

override fun dispose() {
stop()
}
}

/**
* Starts the ProblemGatheringBridge service when the first project opens
*/
class ProblemGatheringBridgeStarter : ProjectActivity, DumbAware {
override suspend fun execute(project: Project) {
ProblemGatheringBridge.getInstance().start()
}
}
3 changes: 2 additions & 1 deletion src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@
<project.converterProvider
implementation="com.github.pushpavel.autocp.common.compat.v0_5_0_eap_1.AutoCpProjectConverterProvider"
id="AutoCp v0.5.0-eap.1"/>
<postStartupActivity implementation="com.github.pushpavel.autocp.gather.base.ProblemGatheringBridge"/>
<applicationService serviceImplementation="com.github.pushpavel.autocp.gather.base.ProblemGatheringBridge"/>
<postStartupActivity implementation="com.github.pushpavel.autocp.gather.base.ProblemGatheringBridgeStarter"/>

<executor implementation="com.github.pushpavel.autocp.core.runner.AutoCpExecutor"/>
<executor implementation="com.github.pushpavel.autocp.core.runner.AutoCpStressExecutor"/>
Expand Down