Skip to content

Commit d813761

Browse files
committed
Emergency commit my Macbook is about to die and the charger is apparently broken
1 parent 9d80945 commit d813761

File tree

4 files changed

+88
-29
lines changed

4 files changed

+88
-29
lines changed

src/main/kotlin/com/demonwav/mcdev/error/AnonymousFeedback.kt

Lines changed: 74 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,20 @@ import java.net.URL
2020

2121
object AnonymousFeedback {
2222

23-
fun sendFeedback(factory: HttpConnectionFactory, envDetails: LinkedHashMap<String, String?>): Int {
24-
return sendFeedback(factory, convertToGitHubIssueFormat(envDetails))
23+
data class FeedbackData(val url: String, val token: Int, val isDuplicate: Boolean)
24+
25+
const val url = "https://www.demonwav.com/errorReport"
26+
27+
fun sendFeedback(factory: HttpConnectionFactory, envDetails: LinkedHashMap<String, String?>): FeedbackData {
28+
val duplicateId = findDuplicateIssue(envDetails)
29+
if (duplicateId != null) {
30+
// This is a duplicate
31+
val commentUrl = sendCommentOnDuplicateIssue(duplicateId, factory, convertToGitHubIssueFormat(envDetails))
32+
return FeedbackData(commentUrl, duplicateId, true)
33+
}
34+
35+
val (htmlUrl, token) = sendFeedback(factory, convertToGitHubIssueFormat(envDetails))
36+
return FeedbackData(htmlUrl, token, false)
2537
}
2638

2739
private fun convertToGitHubIssueFormat(envDetails: LinkedHashMap<String, String?>): ByteArray {
@@ -63,22 +75,8 @@ object AnonymousFeedback {
6375
return sb.toString()
6476
}
6577

66-
private fun sendFeedback(factory: HttpConnectionFactory, payload: ByteArray): Int {
67-
val url = "https://www.demonwav.com/errorReport"
68-
var userAgent = "Minecraft Development IntelliJ IDEA plugin"
69-
70-
val pluginDescriptor = PluginManager.getPlugin(PluginUtil.PLUGIN_ID)
71-
if (pluginDescriptor != null) {
72-
val name = pluginDescriptor.name
73-
val version = pluginDescriptor.version
74-
userAgent = "$name ($version)"
75-
}
76-
77-
val connection = connect(factory, url)
78-
connection.doOutput = true
79-
connection.requestMethod = "POST"
80-
connection.setRequestProperty("User-Agent", userAgent)
81-
connection.setRequestProperty("Content-Type", "application/json")
78+
private fun sendFeedback(factory: HttpConnectionFactory, payload: ByteArray): Pair<String, Int> {
79+
val connection = getConnection(factory, url)
8280
connection.outputStream.use {
8381
it.write(payload)
8482
}
@@ -94,8 +92,7 @@ object AnonymousFeedback {
9492
}
9593

9694
val json = Gson().fromJson<Map<*, *>>(body)
97-
val issueNum = json["number"].toString().toDouble().toInt()
98-
return issueNum
95+
return json["html_url"] as String to (json["id"] as Double).toInt()
9996
}
10097

10198
private fun connect(factory: HttpConnectionFactory, url: String): HttpURLConnection {
@@ -105,6 +102,63 @@ object AnonymousFeedback {
105102
return connection
106103
}
107104

105+
private fun findDuplicateIssue(envDetails: LinkedHashMap<String, String?>): Int? {
106+
val stack = envDetails["error.stacktrace"] ?: return null
107+
108+
val text = URL("https://api.github.com/repos/minecraft-dev/MinecraftDev/issues").readText()
109+
val list = Gson().fromJson<List<Map<*, *>>>(text)
110+
val block = list.firstOrNull {
111+
val body = it["body"] as? String ?: return@firstOrNull false
112+
113+
val first = body.indexOf("\n```\n", startIndex = 0) + 5
114+
val second = body.indexOf("\n```\n", startIndex = first)
115+
val stackText = body.substring(first, second)
116+
117+
stackText == stack
118+
} ?: return null
119+
return (block["id"] as Double).toInt()
120+
}
121+
122+
private fun sendCommentOnDuplicateIssue(id: Int, factory: HttpConnectionFactory, payload: ByteArray): String {
123+
val commentUrl = "$url/$id/comments"
124+
val connection = getConnection(factory, commentUrl)
125+
connection.outputStream.use {
126+
it.write(payload)
127+
}
128+
129+
val responseCode = connection.responseCode
130+
if (responseCode != 201) {
131+
throw RuntimeException("Expected HTTP_CREATED (201), obtained $responseCode instead.")
132+
}
133+
134+
val contentEncoding = connection.contentEncoding ?: "UTF-8"
135+
val body = connection.inputStream.use {
136+
IOUtils.toString(it, contentEncoding)
137+
}
138+
139+
val json = Gson().fromJson<Map<*, *>>(body)
140+
return json["html_url"] as String
141+
}
142+
143+
private fun getConnection(factory: HttpConnectionFactory, url: String): HttpURLConnection {
144+
var userAgent = "Minecraft Development IntelliJ IDEA plugin"
145+
146+
val pluginDescription = PluginManager.getPlugin(PluginUtil.PLUGIN_ID)
147+
if (pluginDescription != null) {
148+
val name = pluginDescription.name
149+
val version = pluginDescription.version
150+
userAgent = "$name ($version)"
151+
}
152+
153+
val connection = connect(factory, url)
154+
connection.doOutput = true
155+
connection.requestMethod = "POST"
156+
connection.setRequestProperty("User-Agent", userAgent)
157+
connection.setRequestProperty("Content-Type", "application/json")
158+
159+
return connection
160+
}
161+
108162
open class HttpConnectionFactory {
109163
open fun openHttpConnection(url: String): HttpURLConnection {
110164
return URL(url).openConnection() as HttpURLConnection

src/main/kotlin/com/demonwav/mcdev/error/AnonymousFeedbackTask.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,16 @@ class AnonymousFeedbackTask(
2121
title: String,
2222
canBeCancelled: Boolean,
2323
private val params: LinkedHashMap<String, String?>,
24-
private val callback: (Int) -> Unit,
24+
private val callback: (String, Int, Boolean) -> Unit,
2525
private val errorCallback: (Exception) -> Unit
2626
) : Task.Backgroundable(project, title, canBeCancelled) {
2727

2828
override fun run(indicator: ProgressIndicator) {
2929
indicator.isIndeterminate = true
3030

3131
try {
32-
val token = AnonymousFeedback.sendFeedback(ProxyHttpConnectionFactory(), params)
33-
callback(token)
32+
val (url, token, isDuplicate) = AnonymousFeedback.sendFeedback(ProxyHttpConnectionFactory(), params)
33+
callback(url, token, isDuplicate)
3434
} catch (e: Exception) {
3535
errorCallback(e)
3636
}

src/main/kotlin/com/demonwav/mcdev/error/ErrorReporter.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,17 @@ class ErrorReporter : ErrorReportSubmitter() {
6868

6969
val project = CommonDataKeys.PROJECT.getData(dataContext)
7070

71-
val task = AnonymousFeedbackTask(project, "Submitting error report", true, reportValues, { token ->
72-
val url = "$baseUrl/$token"
73-
val reportInfo = SubmittedReportInfo(url, "Issue #$token", SubmittedReportInfo.SubmissionStatus.NEW_ISSUE)
71+
val task = AnonymousFeedbackTask(project, "Submitting error report", true, reportValues, { htmlUrl, token, isDuplicate ->
72+
val reportInfo = SubmittedReportInfo(htmlUrl, "Issue #$token", SubmittedReportInfo.SubmissionStatus.NEW_ISSUE)
7473
consumer.consume(reportInfo)
7574

76-
val message = "<html>Created Issue #$token successfully.<br>" +
77-
"<a href=\"$url\">View issue.</a></html>"
75+
val message = if (!isDuplicate) {
76+
"<html>Created Issue #$token successfully.<br>" +
77+
"<a href=\"$htmlUrl\">View issue.</a></html>"
78+
} else {
79+
"<html>Commented on existing Issue #$token successfully.<br>" +
80+
"<a href=\"$htmlUrl\" View issue.</a></html>"
81+
}
7882

7983
ReportMessages.GROUP.createNotification(
8084
ReportMessages.ERROR_REPORT,

src/main/kotlin/com/demonwav/mcdev/nbt/NbtVirtualFile.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiManager
2222
import java.io.ByteArrayInputStream
2323
import java.io.ByteArrayOutputStream
2424
import java.io.DataOutputStream
25+
import java.util.concurrent.TimeUnit
2526
import java.util.zip.GZIPOutputStream
2627

2728
class NbtVirtualFile(private val backingFile: VirtualFile, private val project: Project) : VirtualFile() {
@@ -35,7 +36,7 @@ class NbtVirtualFile(private val backingFile: VirtualFile, private val project:
3536
var tempCompressed: Boolean
3637
var tempParseSuccessful: Boolean
3738
try {
38-
val (rootCompound, isCompressed) = Nbt.buildTagTree(backingFile.inputStream, 1000)
39+
val (rootCompound, isCompressed) = Nbt.buildTagTree(backingFile.inputStream, TimeUnit.SECONDS.toMillis(1))
3940
this.bytes = rootCompound.toString().toByteArray()
4041
tempCompressed = isCompressed
4142
tempParseSuccessful = true

0 commit comments

Comments
 (0)