バージョン比較時にrcを正しく取り扱う。2.4.0rc2以降のタンスでプッシュ購読更新の挙動を最適化。

This commit is contained in:
tateisu 2018-05-14 23:41:13 +09:00
parent 9133f18650
commit f3f25557f7
7 changed files with 180 additions and 86 deletions

View File

@ -241,8 +241,7 @@ class Column(
}
}
internal val version_1_6 = VersionString("1.6")
@Suppress("HasPlatformType")
val reMaxId = Pattern.compile("[&?]max_id=(\\d+)") // より古いデータの取得に使う
@ -1711,7 +1710,7 @@ class Column(
if(with_attachment && ! with_highlight) path += "&only_media=1"
if(instance != null
&& instance.versionGE(version_1_6)
&& instance.versionGE(TootInstance.VERSION_1_6)
// 将来的に正しく判定できる見込みがないので、Pleroma条件でのフィルタは行わない
// && instance.instanceType != TootInstance.InstanceType.Pleroma
) {

View File

@ -180,7 +180,7 @@ class TootApiClient(
}
fun getScopeString(ti : TootInstance) = when {
ti.versionGE(TootInstance.VERSION_2_4_0) -> "read+write+follow+push"
ti.versionGE(TootInstance.VERSION_2_4_0_rc1) -> "read+write+follow+push"
else -> "read+write+follow"
}

View File

@ -10,8 +10,9 @@ class TootInstance(parser : TootParser, src : JSONObject) {
companion object {
private val rePleroma = Pattern.compile("\\bpleroma\\b", Pattern.CASE_INSENSITIVE)
val VERSION_2_4_0 = VersionString("2.4.0")
val VERSION_2_4_1 = VersionString("2.4.1")
val VERSION_1_6 = VersionString("1.6")
val VERSION_2_4_0_rc1 = VersionString("2.4.0rc1")
val VERSION_2_4_0_rc2 = VersionString("2.4.0rc2")
}
@ -106,10 +107,5 @@ class TootInstance(parser : TootParser, src : JSONObject) {
val i = VersionString.compare(decoded_version, check)
return i >= 0
}
fun versionEquals(check : VersionString) : Boolean {
if(decoded_version.isEmpty || check.isEmpty) return false
val i = VersionString.compare(decoded_version, check)
return i == 0
}
}

View File

@ -59,7 +59,7 @@ class PostHelper(
private val reCharsNotTag = Pattern.compile("[・\\s\\-+.,:;/]")
private val reCharsNotEmoji = Pattern.compile("[^0-9A-Za-z_-]")
private val version_1_6 = VersionString("1.6")
}
///////////////////////////////////////////////////////////////////////////////////
@ -205,7 +205,7 @@ class PostHelper(
instance = instance_tmp ?: return r2
account.instance = instance
}
visibility_checked = if(instance.versionGE(version_1_6)) {
visibility_checked = if(instance.versionGE(TootInstance.VERSION_1_6)) {
null
} else {
val r2 = getCredential(client)

View File

@ -2,8 +2,9 @@ package jp.juggler.subwaytooter.util
import java.math.BigInteger
import java.util.ArrayList
import java.util.regex.Pattern
class VersionString(src : String?) {
class VersionString(src : String?) : Comparable<VersionString> {
private val src : String
@ -16,97 +17,143 @@ class VersionString(src : String?) {
return src
}
private class RC(val x : Int) : Comparable<RC> {
override fun compareTo(other : RC) : Int {
val i = x - other.x
return if(i > 0) 1 else if(i < 0) - 1 else 0
}
override fun toString() : String {
return "RC($x)"
}
}
override fun compareTo(other : VersionString) : Int {
return compare(this, other)
}
init {
this.src = src ?: ""
if( src != null && src.isNotEmpty() ){
if(src != null && src.isNotEmpty()) {
val end = src.length
var next = 0
while(next < end) {
var c = src[next]
if(isDelimiter(c)) {
// 先頭の区切り文字を無視する
++ next
} else if(Character.isDigit(c)) {
// 数字列のノード
val start = next ++
while(next < end && Character.isDigit(src[next])) ++ next
val value = BigInteger(src.substring(start, next))
node_list.add(value)
} else {
// 区切り文字と数字以外の文字が並ぶノード
val start = next ++
while(next < end) {
c = src[next]
if(isDelimiter(c)) break
if(Character.isDigit(c)) break
when {
isDelimiter(c) -> {
// 先頭の区切り文字を無視する
++ next
}
val value = src.substring(start, next)
node_list.add(value)
Character.isDigit(c) -> {
// 数字列のノード
val start = next ++
while(next < end && Character.isDigit(src[next])) ++ next
val value = BigInteger(src.substring(start, next))
node_list.add(value)
}
else -> {
val m = reRcX.matcher(src)
if(DUMP) {
if(m.find(next)) {
println("next=$next, matct_start=${m.start()}")
} else {
println("next=$next, not match.")
}
}
if(m.find(next) && m.start() == next) {
// RCード
next = m.end()
val numStr = m.group(1)
val num = if(numStr?.isNotEmpty() == true) {
numStr.toInt()
} else {
0
}
node_list.add(RC(num))
} else {
// 区切り文字と数字以外の文字が並ぶノード
val start = next ++
while(next < end) {
c = src[next]
if(isDelimiter(c)) break
if(Character.isDigit(c)) break
++ next
}
val value = src.substring(start, next)
node_list.add(value)
}
}
}
}
}
}
companion object {
// private val warning = new LogCategory( "VersionString" )
companion object : Comparator<VersionString> {
private const val DUMP = false
private fun isDelimiter(c : Char) : Boolean {
return c == '.' || c == ' '
}
private val reRcX = Pattern.compile("rc(\\d*)")
private fun checkTail(b : Any) : Int {
// 1.0 < 1.0.n => -1
// 1.0 < 1.0xxx => -1
// 1.0 > 1.0rc1 => 1
return if(b is RC) 1 else - 1
}
private fun checkBigInteger(a : BigInteger, b : Any) : Int {
if(b is BigInteger) return a.compareTo(b)
// 数字 > 数字以外
// 1.5.n > 1.5xxx
// 1.5.n > 1.5rc1
return 1
}
private fun checkRc(a : RC, b : Any) : Int {
if(b is RC) return a.compareTo(b)
// RC < string
// 1.5rc < 1.5xxx
return - 1
}
// return -1 if a<b , return 1 if a>b , return 0 if a==b
fun compare(a : VersionString, b : VersionString) : Int {
override fun compare(a : VersionString, b : VersionString) : Int {
var idx = 0
while(true) {
loop@ while(true) {
val ao = if(idx >= a.node_list.size) null else a.node_list[idx]
val bo = if(idx >= b.node_list.size) null else b.node_list[idx]
if(ao == null) {
// 1.0 < 1.0.n
// 1.0 < 1.0 xxx
return if(bo == null) 0 else - 1
} else if(bo == null) {
// 1.0.n > 1.0
// 1.0 xxx > 1.0
return 1
}
if(DUMP) println("a=$ao,b=$bo")
return if(ao is BigInteger) {
if(bo is BigInteger) {
// 数字同士の場合
val i = ao.compareTo(bo)
if(i == 0) {
++ idx
continue
}else {
i
}
} else {
// 数字 > 数字以外
// 1.5.n > 1.5 xxx
1
val i = when {
ao == null -> {
if(bo == null) return 0
checkTail(bo)
}
} else if(bo is BigInteger) {
// 数字以外 < 数字
// 1.5 xxx < 1.5.n
- 1
} else if( ao is String && bo is String ){
// 文字列どうしは辞書順で比較
val i =ao.compareTo(bo )
if(i == 0) {
++ idx
continue
}
i
}else{
throw RuntimeException("node is not string")
bo == null -> - checkTail(ao)
ao is BigInteger -> checkBigInteger(ao, bo)
bo is BigInteger -> - checkBigInteger(bo, ao)
ao is RC -> checkRc(ao, bo)
bo is RC -> - checkRc(bo, ao)
else -> a.toString().compareTo(b.toString())
}
if(i == 0) {
++ idx
continue@loop
}
return i
}
}
}
}

View File

@ -81,8 +81,8 @@ class WebPushSubscription(
r = client.getInstanceInformation2()
val ti = r?.data as? TootInstance ?: return r
if(! ti.versionGE(TootInstance.VERSION_2_4_0)) {
// 2.3.x 以下にはプッシュ購読APIはない
if( ! ti.versionGE(TootInstance.VERSION_2_4_0_rc1)) {
// 2.4.0rc1 未満にはプッシュ購読APIはない
return TootApiResult(
error = context.getString(
R.string.instance_does_not_support_push_api,
@ -92,15 +92,13 @@ class WebPushSubscription(
}
if(subscription404 && flags == 0) {
if(ti.versionGE(TootInstance.VERSION_2_4_1)
|| ti.versionEquals(TootInstance.VERSION_2_4_0)
) {
if(ti.versionGE(TootInstance.VERSION_2_4_0_rc2) ) {
// 購読が不要で現在の状況が404だった場合
// 2.4.0正式版と2.4.1以降では購読が存在しないので何もしなくてよい
// 2.4.0rc2以降では「購読が存在しない」を示すので何もしなくてよい
if(verbose) addLog(context.getString(R.string.push_subscription_not_exists))
return TootApiResult()
} else {
// コミット単位でバージョン比較する方法はないので、2.4.0正式ではない2.4.0xxxでは存在確認はできない
// 2.4.0rc1では「APIが存在しない」と「購読が存在しない」を判別できない
}
}
}

View File

@ -0,0 +1,54 @@
@file:Suppress(
"USELESS_CAST", "unused", "DEPRECATED_IDENTITY_EQUALS", "UNUSED_VARIABLE",
"UNUSED_VALUE", "ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE", "VARIABLE_WITH_REDUNDANT_INITIALIZER",
"ReplaceCallWithComparison"
)
package jp.juggler.subwaytooter
import jp.juggler.subwaytooter.util.VersionString
import org.junit.Test
import org.junit.Assert.*
class TestVersionString {
@Test
fun test1() {
val v233 = VersionString("2.3.3")
val v240rc0 = VersionString("2.4.0rc")
val v240rc1 = VersionString("2.4.0rc1")
val v240rc2 = VersionString("2.4.0rc2")
val v240 = VersionString("2.4.0")
val v240xxx = VersionString("2.4.0xxx")
val v241 = VersionString("2.4.1")
assertTrue(v233 < v240rc0)
assertTrue(v240rc0 < v240rc1)
assertTrue(v240rc1 < v240rc2)
assertTrue(v240rc2 < v240)
assertTrue(v240 < v240xxx)
assertTrue(v240xxx < v241)
assertTrue(v240rc0 > v233)
assertTrue(v240rc1 > v240rc0)
assertTrue(v240rc2 > v240rc1)
assertTrue(v240 > v240rc2)
assertTrue(v240xxx > v240)
assertTrue(v241 > v240xxx)
assertTrue(0 == v233.compareTo(v233))
assertTrue(0 == v240rc0.compareTo(v240rc0))
assertTrue(0 == v240rc1.compareTo(v240rc1))
assertTrue(0 == v240rc2.compareTo(v240rc2))
assertTrue(0 == v240.compareTo(v240))
assertTrue(0 == v240xxx.compareTo(v240xxx))
assertTrue(0 == v241.compareTo(v241))
}
@Test
fun test2() {
val v240 = VersionString("2.4.0")
val v240xxx = VersionString("2.4.0xxx")
assertTrue(v240 < v240xxx)
}
}