Skip to content

Commit

Permalink
Offline mode (close #10)
Browse files Browse the repository at this point in the history
Omitting the Home Assistant URL will make the plugin clear its caches and work with what it has (i.e. local data with in the configuration files)
  • Loading branch information
daniele-athome committed Feb 10, 2025
1 parent 3ba48da commit c960d7f
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ class HassFacetEditorTab(

manager.registerValidator(object : FacetEditorValidator() {
override fun check(): ValidationResult {
// empty URL means offline usage
if (component.instanceUrl.isBlank()) {
return ValidationResult.OK
}

val url = try {
Urls.parse(component.instanceUrl, false)
} catch (_: Exception) {
Expand All @@ -45,7 +50,12 @@ class HassFacetEditorTab(

manager.registerValidator(object : FacetEditorValidator() {
override fun check(): ValidationResult {
return if (component.token.trim().isNotEmpty()) {
// empty URL means offline usage, so we don't need a token
if (component.instanceUrl.isBlank()) {
return ValidationResult.OK
}

return if (component.token.isNotBlank()) {
ValidationResult.OK
} else {
ValidationResult(MyBundle.message("hass.facet.editor.token.invalid"))
Expand All @@ -68,8 +78,8 @@ class HassFacetEditorTab(
@Throws(ConfigurationException::class)
override fun apply() {
try {
state.instanceUrl = component.instanceUrl
state.token = component.token
state.instanceUrl = component.instanceUrl.trim()
state.token = component.token.trim()

// trigger download immediately
val service = HassRemoteRepository.getInstance(context.project)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import java.io.InputStream
import java.nio.file.Path
import java.util.concurrent.locks.ReentrantReadWriteLock
import kotlin.concurrent.write
import kotlin.io.path.deleteIfExists
import kotlin.io.path.isReadable
import kotlin.io.path.isRegularFile
import kotlin.io.path.pathString
Expand Down Expand Up @@ -184,6 +185,10 @@ open class HassRemoteRepository(private val project: Project, private val cs: Co
return cacheFile.isRegularFile() && cacheFile.isReadable()
}

private fun isOfflineMode(module: Module): Boolean {
return getConfiguration(module)?.instanceUrl?.isBlank() ?: true
}

/**
* Refresh all Home Assistant data caches.
* @return true if at least one refresh from network was triggered.
Expand All @@ -194,6 +199,12 @@ open class HassRemoteRepository(private val project: Project, private val cs: Co
}

private fun refreshServices(module: Module, force: Boolean = false): Boolean {
if (isOfflineMode(module)) {
// delete local cache file
getServicesCacheFile(module).deleteIfExists()
return true
}

// TODO maybe invalidate the cache after some time?
if (!isServicesCacheAvailable(module) || force) {
downloadServices(module)
Expand All @@ -203,6 +214,12 @@ open class HassRemoteRepository(private val project: Project, private val cs: Co
}

private fun refreshStates(module: Module, force: Boolean = false): Boolean {
if (isOfflineMode(module)) {
// delete local cache file
getStatesCacheFile(module).deleteIfExists()
return true
}

// TODO maybe invalidate the cache after some time?
if (!isStatesCacheAvailable(module) || force) {
downloadStates(module)
Expand All @@ -219,7 +236,9 @@ open class HassRemoteRepository(private val project: Project, private val cs: Co
module,
SERVICES_CACHE,
{
val result: Collection<JsonProperty>? = if (isServicesCacheAvailable(module)) {
val result: Collection<JsonProperty>? = if (isOfflineMode(module)) {
null
} else if (isServicesCacheAvailable(module)) {
ReadAction.compute<Collection<JsonProperty>, Throwable> {
try {
val virtualFile = LocalFileSystem.getInstance()
Expand Down Expand Up @@ -274,7 +293,9 @@ open class HassRemoteRepository(private val project: Project, private val cs: Co
module,
getStatesCacheKey(*excludeDomains),
{
val result: Collection<JsonStringLiteral>? = if (isStatesCacheAvailable(module)) {
val result: Collection<JsonStringLiteral>? = if (isOfflineMode(module)) {
null
} else if (isStatesCacheAvailable(module)) {
ReadAction.compute<Collection<JsonStringLiteral>, Throwable> {
try {
val virtualFile = LocalFileSystem.getInstance()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,27 @@ class ProjectSettingsConfigurable(private val project: Project) : Configurable {
override fun apply() {
val other = settingsComponent!!

val url = try {
Urls.parse(other.instanceUrl, false)
} catch (_: Exception) {
null
}
// empty URL means offline usage
if (other.instanceUrl.isNotBlank()) {
val url = try {
Urls.parse(other.instanceUrl, false)
} catch (_: Exception) {
null
}

if (url == null) {
@Suppress("DialogTitleCapitalization")
throw ConfigurationException(MyBundle.message("hass.facet.editor.instanceUrl.invalid"))
}
if (url == null) {
@Suppress("DialogTitleCapitalization")
throw ConfigurationException(MyBundle.message("hass.facet.editor.instanceUrl.invalid"))
}

if (other.token.trim().isEmpty()) {
throw ConfigurationException(MyBundle.message("hass.facet.editor.token.invalid"))
if (other.token.isBlank()) {
throw ConfigurationException(MyBundle.message("hass.facet.editor.token.invalid"))
}
}

val state = ProjectSettings.getInstance(project).state
state.instanceUrl = other.instanceUrl
state.token = other.token
state.instanceUrl = other.instanceUrl.trim()
state.token = other.token.trim()

// trigger download immediately
val service = HassRemoteRepository.getInstance(project)
Expand Down

0 comments on commit c960d7f

Please sign in to comment.