@@ -12,9 +12,11 @@ package com.demonwav.mcdev.error
1212
1313import com.demonwav.mcdev.update.PluginUtil
1414import com.demonwav.mcdev.util.fromJson
15- import com.google.gson.Gson
15+ import com.demonwav.mcdev.util.gson
1616import com.intellij.ide.plugins.PluginManager
17+ import com.intellij.util.io.readCharSequence
1718import org.apache.commons.io.IOUtils
19+ import java.io.InputStreamReader
1820import java.net.HttpURLConnection
1921import java.net.URL
2022
@@ -25,7 +27,7 @@ object AnonymousFeedback {
2527 const val url = " https://www.demonwav.com/errorReport"
2628
2729 fun sendFeedback (factory : HttpConnectionFactory , envDetails : LinkedHashMap <String , String ?>): FeedbackData {
28- val duplicateId = findDuplicateIssue(envDetails)
30+ val duplicateId = findDuplicateIssue(envDetails, factory )
2931 if (duplicateId != null ) {
3032 // This is a duplicate
3133 val commentUrl = sendCommentOnDuplicateIssue(duplicateId, factory, convertToGitHubIssueFormat(envDetails))
@@ -40,7 +42,7 @@ object AnonymousFeedback {
4042 val result = LinkedHashMap <String , String >(5 )
4143 result.put(" title" , " [auto-generated] Exception in plugin" )
4244 result.put(" body" , generateGitHubIssueBody(envDetails))
43- return Gson () .toJson(result).toByteArray()
45+ return gson .toJson(result).toByteArray()
4446 }
4547
4648 private fun generateGitHubIssueBody (body : LinkedHashMap <String , String ?>): String {
@@ -77,6 +79,7 @@ object AnonymousFeedback {
7779
7880 private fun sendFeedback (factory : HttpConnectionFactory , payload : ByteArray ): Pair <String , Int > {
7981 val connection = getConnection(factory, url)
82+ connection.connect()
8083 connection.outputStream.use {
8184 it.write(payload)
8285 }
@@ -90,8 +93,9 @@ object AnonymousFeedback {
9093 val body = connection.inputStream.use {
9194 IOUtils .toString(it, contentEncoding)
9295 }
96+ connection.disconnect()
9397
94- val json = Gson () .fromJson<Map <* , * >>(body)
98+ val json = gson .fromJson<Map <* , * >>(body)
9599 return json[" html_url" ] as String to (json[" number" ] as Double ).toInt()
96100 }
97101
@@ -102,11 +106,11 @@ object AnonymousFeedback {
102106 return connection
103107 }
104108
105- private fun findDuplicateIssue (envDetails : LinkedHashMap <String , String ?>): Int? {
109+ private fun findDuplicateIssue (envDetails : LinkedHashMap <String , String ?>, factory : HttpConnectionFactory ): Int? {
106110 val stack = envDetails[" error.stacktrace" ]?.replace(" \\ d+" .toRegex(), " " ) ? : return null
107111
108- val text = URL (" https://api.github.com/repos/minecraft-dev/MinecraftDev/issues?state=all&creator=minecraft-dev-autoreporter " ).readText()
109- val list = Gson ().fromJson< List < Map < * , * >>>(text)
112+ val list = getAllIssues (" https://api.github.com/repos/minecraft-dev/MinecraftDev/issues" +
113+ " ?state=all&creator=minecraft-dev-autoreporter&per_page=100 " , factory) ? : return null
110114 val block = list.firstOrNull {
111115 val body = it[" body" ] as ? String ? : return @firstOrNull false
112116
@@ -124,6 +128,65 @@ object AnonymousFeedback {
124128 return (block[" number" ] as Double ).toInt()
125129 }
126130
131+ private fun getAllIssues (url : String , factory : HttpConnectionFactory ): List <Map <* , * >>? {
132+ var connection = connect(factory, url)
133+ connection.requestMethod = " GET"
134+ connection.setRequestProperty(" User-Agent" , userAgent)
135+
136+ connection.connect()
137+ if (connection.responseCode != 200 ) {
138+ connection.disconnect()
139+ return null
140+ }
141+
142+ val list = mutableListOf<Map <* , * >>()
143+ var data = connection.inputStream.reader().use(InputStreamReader ::readCharSequence).toString()
144+
145+ var response = gson.fromJson<List <Map <* , * >>>(data)
146+ list.addAll(response)
147+
148+ var link = connection.getHeaderField(" Link" )
149+ connection.disconnect()
150+
151+ var next = getNextLink(link)
152+ while (next != null ) {
153+ connection = connect(factory, next)
154+ connection.requestMethod = " GET"
155+ connection.setRequestProperty(" User-Agent" , userAgent)
156+
157+ connection.connect()
158+ if (connection.responseCode != 200 ) {
159+ connection.disconnect()
160+ continue
161+ }
162+
163+ data = connection.inputStream.reader().use(InputStreamReader ::readCharSequence).toString()
164+
165+ response = gson.fromJson<List <Map <* , * >>>(data)
166+ list.addAll(response)
167+
168+ link = connection.getHeaderField(" Link" )
169+ connection.disconnect()
170+ next = getNextLink(link)
171+ }
172+
173+ return list
174+ }
175+
176+ private fun getNextLink (link : String ): String? {
177+ val lines = link.split(" ," )
178+ for (line in lines) {
179+ if (! line.contains(" rel=\" next\" " )) {
180+ continue
181+ }
182+
183+ val parts = line.split(" ;" )
184+ return parts[0 ].substring(1 , parts[0 ].length- 1 )
185+ }
186+
187+ return null
188+ }
189+
127190 private fun sendCommentOnDuplicateIssue (id : Int , factory : HttpConnectionFactory , payload : ByteArray ): String {
128191 val commentUrl = " $url /$id /comments"
129192 val connection = getConnection(factory, commentUrl)
@@ -140,21 +203,13 @@ object AnonymousFeedback {
140203 val body = connection.inputStream.use {
141204 IOUtils .toString(it, contentEncoding)
142205 }
206+ connection.disconnect()
143207
144- val json = Gson () .fromJson<Map <* , * >>(body)
208+ val json = gson .fromJson<Map <* , * >>(body)
145209 return json[" html_url" ] as String
146210 }
147211
148212 private fun getConnection (factory : HttpConnectionFactory , url : String ): HttpURLConnection {
149- var userAgent = " Minecraft Development IntelliJ IDEA plugin"
150-
151- val pluginDescription = PluginManager .getPlugin(PluginUtil .PLUGIN_ID )
152- if (pluginDescription != null ) {
153- val name = pluginDescription.name
154- val version = pluginDescription.version
155- userAgent = " $name ($version )"
156- }
157-
158213 val connection = connect(factory, url)
159214 connection.doOutput = true
160215 connection.requestMethod = " POST"
@@ -164,6 +219,18 @@ object AnonymousFeedback {
164219 return connection
165220 }
166221
222+ private val userAgent by lazy {
223+ var agent = " Minecraft Development IntelliJ IDEA plugin"
224+
225+ val pluginDescription = PluginManager .getPlugin(PluginUtil .PLUGIN_ID )
226+ if (pluginDescription != null ) {
227+ val name = pluginDescription.name
228+ val version = pluginDescription.version
229+ agent = " $name ($version )"
230+ }
231+ agent
232+ }
233+
167234 open class HttpConnectionFactory {
168235 open fun openHttpConnection (url : String ) = URL (url).openConnection() as HttpURLConnection
169236 }
0 commit comments