Unverified Commit 52c586f9 authored by Oleksandr Karpovich's avatar Oleksandr Karpovich Committed by GitHub

Implement hostOs detection for web target (#738)

* Implement hostOs detection for web target

* Refactor hostOs initialization in OsArch.js.kt

Instead of using a lazy initialization, this change allows immediate initialization.

* Deprecate incorrect enum OS.JS value in OsArch.kt

Deprecation annotation has been added to JS enum in OsArch. This is done as 'JS' is not a valid host OS name. Added 'Unknown' enum for undefined or unknown cases to handle from now on. Consider using enum 'KotlinBackend' to detect JS.

* Deprecate invalid Arch values and modify hostArch

The Arch values 'JS' and 'WASM' were deprecated as they were found to be invalid. An 'Unknown' value was introduced to accommodate for unforeseen cases in the future. The 'hostArch' value under 'OsArch.js.kt' has been updated accordingly to use this new 'Unknown' value.

* Add OS.Unknown to `when` expressions to make them exhaustive
parent ff7ef4c3
......@@ -36,7 +36,7 @@ internal actual fun makeDefaultRenderFactory(): RenderFactory =
GraphicsApi.SOFTWARE_FAST -> LinuxSoftwareRedrawer(layer, analytics, properties)
else -> LinuxOpenGLRedrawer(layer, analytics, properties)
}
OS.Android, OS.JS, OS.Ios -> throw UnsupportedOperationException("The AWT target doesn't support $hostOs")
OS.Android, OS.JS, OS.Ios, OS.Unknown -> throw UnsupportedOperationException("The AWT target doesn't support $hostOs")
}
}
......
......@@ -125,7 +125,7 @@ internal val platformOperations: PlatformOperations by lazy {
}
}
OS.Android -> TODO()
OS.JS, OS.Ios -> {
OS.JS, OS.Ios, OS.Unknown -> {
TODO("Commonize me")
}
}
......
......@@ -6,7 +6,10 @@ enum class OS(val id: String) {
Windows("windows"),
MacOS("macos"),
Ios("ios"),
JS("js")
@Deprecated("JS is invalid host OS name. Consider using enum KotlinBackend to detect JS.")
JS("js"),
Unknown("unknown")
;
val isLinux
......@@ -22,14 +25,19 @@ enum class OS(val id: String) {
enum class Arch(val id: String) {
X64("x64"),
Arm64("arm64"),
@Deprecated("JS is not valid Arch value")
JS("js"),
WASM("wasm")
@Deprecated("WASM is not valid Arch value")
WASM("wasm"),
Unknown("unknown"),
;
}
enum class KotlinBackend(val id: String) {
JVM("jvm"),
JS("js"),
Native("native"),
WASM("wasm"),
;
fun isNotJs() = this != JS
......
package org.jetbrains.skiko
actual val hostOs: OS = OS.JS
import kotlinx.browser.window
actual val hostArch: Arch = Arch.JS
actual val hostOs: OS = detectHostOs()
actual val hostArch: Arch = Arch.Unknown
actual val hostId by lazy {
"${hostOs.id}-${hostArch.id}"
}
actual val kotlinBackend: KotlinBackend
get() = KotlinBackend.JS
\ No newline at end of file
get() = KotlinBackend.JS
/**
* A string identifying the platform on which the user's browser is running; for example:
* "MacIntel", "Win32", "Linux x86_64", "Linux x86_64".
* See https://developer.mozilla.org/en-US/docs/Web/API/Navigator/platform - deprecated
*
* A string containing the platform brand. For example, "Windows".
* See https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/platform - new API,
* but not supported in all browsers
*/
private fun getNavigatorInfo(): String =
js("navigator.userAgentData ? navigator.userAgentData.platform : navigator.platform") as String
/**
* In a browser, user platform can be obtained from different places:
* - we attempt to use not-deprecated but experimental option first (not available in all browsers)
* - then we attempt to use a deprecated option
* - if both above return an empty string, we attempt to get `Platform` from `userAgent`
*
* Note: a client can spoof these values, so it's okay only for non-critical use cases.
*/
internal fun detectHostOs(): OS {
val platformInfo = getNavigatorInfo().takeIf {
it.isNotEmpty()
} ?: window.navigator.userAgent
return when {
platformInfo.contains("Android", true) -> OS.Android
platformInfo.contains("iPhone", true) -> OS.Ios
platformInfo.contains("iOS", true) -> OS.Ios
platformInfo.contains("iPad", true) -> OS.Ios
platformInfo.contains("Linux", true) -> OS.Linux
platformInfo.contains("Mac", true) -> OS.MacOS
platformInfo.contains("Win", true) -> OS.Windows
else -> OS.Unknown
}
}
\ No newline at end of file
package org.jetbrains.skiko.tests.org.jetbrains.skiko
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.detectHostOs
import org.jetbrains.skiko.hostOs
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
class HostOsTest {
@Test
fun canGetHostOs() {
assertNotEquals(OS.JS, hostOs)
}
@Test
fun canGetLinux() {
spoofUserAgentData("linux")
assertEquals(OS.Linux, detectHostOs())
}
@Test
fun canGetWindows() {
spoofUserAgentData("Windows")
assertEquals(OS.Windows, detectHostOs())
}
@Test
fun canGetMacos() {
spoofUserAgentData("macos")
assertEquals(OS.MacOS, detectHostOs())
}
@Test
fun canGetAndroid() {
spoofUserAgentData("android")
assertEquals(OS.Android, detectHostOs())
}
@Test
fun canGetIos() {
spoofUserAgentData("ios")
assertEquals(OS.Ios, detectHostOs())
}
@Test
fun fallbackToUnknown() {
spoofUserAgentData("somerandomedata")
assertEquals(OS.Unknown, detectHostOs())
}
}
private fun spoofUserAgentData(newValue: String) =
js("""navigator.__defineGetter__('userAgentData', function () { return { platform:newValue }; });""")
......@@ -70,7 +70,7 @@ object SkikoProperties {
OS.Linux -> return GraphicsApi.OPENGL
OS.Windows -> return GraphicsApi.DIRECT3D
OS.Android -> return GraphicsApi.OPENGL
OS.JS, OS.Ios -> TODO("commonize me")
OS.JS, OS.Ios, OS.Unknown -> TODO("commonize me")
}
}
......@@ -84,7 +84,7 @@ object SkikoProperties {
else -> listOf(GraphicsApi.DIRECT3D, GraphicsApi.OPENGL, GraphicsApi.SOFTWARE_FAST, GraphicsApi.SOFTWARE_COMPAT)
}
OS.Android -> return listOf(GraphicsApi.OPENGL)
OS.JS, OS.Ios -> TODO("commonize me")
OS.JS, OS.Ios, OS.Unknown -> TODO("commonize me")
}
val indexOfInitialApi = fallbackApis.indexOf(initialApi)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment