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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/.gradle/
/build/
65 changes: 17 additions & 48 deletions src/main/kotlin/com/platfom/sync/FilesDetectionsListener.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,38 @@ import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.fileEditor.FileEditorManagerListener
import com.intellij.openapi.vfs.VirtualFile
import org.java_websocket.client.WebSocketClient
import org.java_websocket.handshake.ServerHandshake
import com.platfom.sync.service.PlatformSyncService
import com.platfom.sync.service.WebSocketService
import java.io.File
import java.net.URI

class FilesDetectionsListener : FileEditorManagerListener {
private val socks = WebSocks(URI("ws://localhost:8123/platform"))
private val editorEventMulticasts = EditorFactory.getInstance().eventMulticaster
private val platformSyncService = PlatformSyncService.getInstance()
private val webSocketService = WebSocketService.getInstance()
private val editorEventMulticaster = EditorFactory.getInstance().eventMulticaster
private var recentLine = -1
private var recentPath = ""

init {
socks.connect()
webSocketService.connect()
}

private val mouseEditorObserver = object : EditorMouseListener {
override fun mouseClicked(event: EditorMouseEvent) {
super.mouseClicked(event)

val newLinePosition = event.editor.caretModel.currentCaret.logicalPosition.line + 1

if (socks.isOpen) {
if (newLinePosition != recentLine) {
recentLine = newLinePosition
socks.send("line===${recentLine}")
val logicalPosition = event.editor.caretModel.logicalPosition.line + 1
if (logicalPosition != recentLine) {
recentLine = logicalPosition
if (webSocketService.isConnected()) {
webSocketService.sendMessage("reviewerUsername===${platformSyncService.getReviewerUsername()};line===$recentLine")
}
}
}
}

override fun fileClosed(source: FileEditorManager, file: VirtualFile) {
super.fileClosed(source, file)
editorEventMulticasts.removeEditorMouseListener(mouseEditorObserver)
}

override fun selectionChanged(editorEvent: FileEditorManagerEvent) {
super.selectionChanged(editorEvent)
editorEvent.newFile?.let {
process(editorEvent.manager, it)
}
}
override fun selectionChanged(event: FileEditorManagerEvent) {
val source = event.manager
val file = event.newFile ?: return

override fun fileOpened(source: FileEditorManager, file: VirtualFile) {
super.fileOpened(source, file)
editorEventMulticasts.addEditorMouseListener(mouseEditorObserver)
editorEventMulticaster.addEditorMouseListener(mouseEditorObserver)
process(source, file)
}

Expand All @@ -61,30 +48,12 @@ class FilesDetectionsListener : FileEditorManagerListener {
val projectLocation = fullPath.split(baseProjectPath)[0]
val filePath = fullPath.replace(projectLocation, "")

if (socks.isOpen) {
if (webSocketService.isConnected()) {
val newPath = filePath.replace("[/\\\\]".toRegex(), "::")
if (newPath != recentPath) {
recentPath = newPath
socks.send("path===${recentPath}")
webSocketService.sendMessage("reviewerUsername===${platformSyncService.getReviewerUsername()};path===${recentPath}")
}
}
}

class WebSocks(uri: URI) : WebSocketClient(uri) {
override fun onOpen(handshakedata: ServerHandshake?) {
println("connected, ready to observe")
}

override fun onMessage(message: String?) {
println("incomming $message")
}

override fun onClose(code: Int, reason: String?, remote: Boolean) {
println("connection close")
}

override fun onError(ex: Exception?) {
println("connection error")
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.platfom.sync.action

import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.platfom.sync.service.PlatformSyncService
import com.platfom.sync.service.WebSocketService

class PlatformSyncStatusAction : AnAction("Status") {
private val webSocketService = WebSocketService.getInstance()

override fun update(e: AnActionEvent) {
val service = PlatformSyncService.getInstance()
val status = service.getPlatformSyncStatus()
val isConnected = webSocketService.isConnected()
e.presentation.text = "Status: ${status.description} (Click to ${if (isConnected) "Disconnect" else "Reconnect"})"
}

override fun actionPerformed(e: AnActionEvent) {
if (webSocketService.isConnected()) {
webSocketService.disconnect()
} else {
webSocketService.connect()
}
}

override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.platfom.sync.action

import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.ui.Messages
import com.platfom.sync.service.PlatformSyncService

class ReviewerUsernameInputAction : AnAction("Reviewer Username Input") {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project
val service = PlatformSyncService.getInstance()

val input = Messages.showInputDialog(
project,
"Input your username",
"Reviewer Username",
Messages.getQuestionIcon()
)

if (!input.isNullOrEmpty()) {
service.saveReviewerUsername(input)
}
}

override fun update(e: AnActionEvent) {
val storedData = PlatformSyncService.getInstance().getReviewerUsername()
e.presentation.text = if (storedData.isNullOrEmpty()) "Input Your Username" else "Reviewer Username: $storedData"
}

override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.EDT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.platfom.sync.service

import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.service

@State(name = "PlatformSyncService", storages = [Storage("PlatformSyncService.xml")])
class PlatformSyncService : PersistentStateComponent<PlatformSyncService.State> {

private val listeners = mutableListOf<() -> Unit>()

data class State(var reviewerUserName: String? = null, var platformSyncStatus: PlatformSyncStatus = PlatformSyncStatus.FAILED_TO_CONNECT)

private var state = State()

override fun getState(): State = state

override fun loadState(state: State) {
this.state = state
}

fun saveReviewerUsername(username: String) {
state.reviewerUserName = username
notifyListeners()
}

fun getReviewerUsername(): String? = state.reviewerUserName

fun savePlatformSyncStatus(status: PlatformSyncStatus) {
state.platformSyncStatus = status
notifyListeners()
}

fun getPlatformSyncStatus(): PlatformSyncStatus = state.platformSyncStatus

fun addChangeListener(listener: () -> Unit) {
listeners.add(listener)
}

fun removeChangeListener(listener: () -> Unit) {
listeners.remove(listener)
}

private fun notifyListeners() {
listeners.forEach { it() }
}

companion object {
fun getInstance(): PlatformSyncService = service()
}
}

enum class PlatformSyncStatus(val description: String) {
CONNECTED("Connected"),
DISCONNECTED("Disconnected"),
FAILED_TO_CONNECT("Failed to Connect")
}
92 changes: 92 additions & 0 deletions src/main/kotlin/com/platfom/sync/service/WebSocketService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.platfom.sync.service

import com.intellij.notification.NotificationGroupManager
import com.intellij.notification.NotificationType
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import org.java_websocket.client.WebSocketClient
import org.java_websocket.handshake.ServerHandshake
import java.net.URI

@Service
class WebSocketService {
private var webSocketClient: WebSocks? = null
private val platformSyncService = PlatformSyncService.getInstance()
private val listeners = mutableListOf<() -> Unit>()

fun connect(): Boolean {
val username = platformSyncService.getReviewerUsername()
if (username.isNullOrEmpty()) {
showNotification("Username not set", "Please set your reviewer username before connecting", NotificationType.WARNING)
return false
}

disconnect()
webSocketClient = WebSocks(platformSyncService, URI("wss://platform-sync-websocket.onrender.com")).apply {
connect()
}
notifyListeners()
return true
}

private fun showNotification(title: String, content: String, type: NotificationType) {
NotificationGroupManager.getInstance()
.getNotificationGroup("Platform Sync Notification")
.createNotification(title, content, type)
.notify(null)
}

fun disconnect() {
webSocketClient?.close()
webSocketClient = null
notifyListeners()
}

fun sendMessage(message: String) {
if (webSocketClient?.isOpen == true) {
webSocketClient?.send(message)
}
}

fun isConnected() = webSocketClient?.isOpen == true

fun addChangeListener(listener: () -> Unit) {
listeners.add(listener)
}

fun removeChangeListener(listener: () -> Unit) {
listeners.remove(listener)
}

private fun notifyListeners() {
listeners.forEach { it() }
}

private inner class WebSocks(private val platformSyncService: PlatformSyncService, uri: URI) : WebSocketClient(uri) {
override fun onOpen(handshakedata: ServerHandshake?) {
platformSyncService.savePlatformSyncStatus(PlatformSyncStatus.CONNECTED)
println("connected, ready to observe")
notifyListeners()
}

override fun onMessage(message: String?) {
println("incoming $message")
}

override fun onClose(code: Int, reason: String?, remote: Boolean) {
platformSyncService.savePlatformSyncStatus(PlatformSyncStatus.DISCONNECTED)
println("connection close")
notifyListeners()
}

override fun onError(ex: Exception?) {
platformSyncService.savePlatformSyncStatus(PlatformSyncStatus.FAILED_TO_CONNECT)
println("connection error")
notifyListeners()
}
}

companion object {
fun getInstance(): WebSocketService = service()
}
}
Loading