@@ -20,8 +20,20 @@ import java.net.URL
2020
2121object 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
0 commit comments