admin: add status text

Signed-off-by: Varun Patil <varunpatil@ucla.edu>
pull/563/head
Varun Patil 2023-04-10 00:20:17 -07:00
parent 203cb146c8
commit 8c1432af45
4 changed files with 173 additions and 9 deletions

View File

@ -83,6 +83,7 @@ return [
// Config API // Config API
['name' => 'Other#setUserConfig', 'url' => '/api/config/{key}', 'verb' => 'PUT'], ['name' => 'Other#setUserConfig', 'url' => '/api/config/{key}', 'verb' => 'PUT'],
['name' => 'Other#getSystemStatus', 'url' => '/api/system-status', 'verb' => 'GET'],
['name' => 'Other#getSystemConfig', 'url' => '/api/system-config', 'verb' => 'GET'], ['name' => 'Other#getSystemConfig', 'url' => '/api/system-config', 'verb' => 'GET'],
['name' => 'Other#setSystemConfig', 'url' => '/api/system-config/{key}', 'verb' => 'PUT'], ['name' => 'Other#setSystemConfig', 'url' => '/api/system-config/{key}', 'verb' => 'PUT'],

View File

@ -25,6 +25,7 @@ namespace OCA\Memories\Controller;
use OCA\Memories\AppInfo\Application; use OCA\Memories\AppInfo\Application;
use OCA\Memories\Exceptions; use OCA\Memories\Exceptions;
use OCA\Memories\Exif;
use OCA\Memories\Util; use OCA\Memories\Util;
use OCP\AppFramework\Http; use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\JSONResponse;
@ -76,8 +77,6 @@ class OtherController extends GenericApiController
/** /**
* @AdminRequired * @AdminRequired
* *
* @NoCSRFRequired
*
* @param mixed $value * @param mixed $value
*/ */
public function setSystemConfig(string $key, $value): Http\Response public function setSystemConfig(string $key, $value): Http\Response
@ -109,6 +108,43 @@ class OtherController extends GenericApiController
}); });
} }
/**
* @AdminRequired
*
* @NoCSRFRequired
*/
public function getSystemStatus(): Http\Response
{
return Util::guardEx(function () {
$status = [];
// Check exiftool
$status['exiftool'] = $this->getExecutableStatus(Util::getSystemConfig('memories.exiftool'));
// Check for system perl
$status['perl'] = $this->getExecutableStatus(exec('which perl'));
// Check ffmpeg and ffprobe binaries
$status['ffmpeg'] = $this->getExecutableStatus(Util::getSystemConfig('memories.vod.ffmpeg'));
$status['ffprobe'] = $this->getExecutableStatus(Util::getSystemConfig('memories.vod.ffprobe'));
// Check go-vod binary
$status['govod'] = $this->getExecutableStatus(Util::getSystemConfig('memories.vod.path'));
// Check for VA-API device
$devPath = '/dev/dri/renderD128';
if (!is_file($devPath)) {
$status['vaapi_dev'] = 'not_found';
} elseif (!is_readable($devPath)) {
$status['vaapi_dev'] = 'not_readable';
} else {
$status['vaapi_dev'] = 'ok';
}
return new JSONResponse($status, Http::STATUS_OK);
});
}
/** /**
* @NoAdminRequired * @NoAdminRequired
* *
@ -127,4 +163,17 @@ class OtherController extends GenericApiController
return $response; return $response;
} }
private function getExecutableStatus(string $path): string
{
if (!is_file($path)) {
return 'not_found';
}
if (!is_executable($path)) {
return 'not_executable';
}
return 'ok';
}
} }

View File

@ -2,6 +2,12 @@
<div class="outer" v-if="loaded"> <div class="outer" v-if="loaded">
<h2>{{ t("memories", "EXIF Extraction") }}</h2> <h2>{{ t("memories", "EXIF Extraction") }}</h2>
<template v-if="status">
<NcNoteCard :type="binaryStatusType(status.exiftool)">
{{ binaryStatus("exiftool", status.exiftool) }}
</NcNoteCard>
</template>
<NcTextField <NcTextField
:label="t('memories', 'Path to packaged exiftool binary')" :label="t('memories', 'Path to packaged exiftool binary')"
:label-visible="true" :label-visible="true"
@ -10,6 +16,12 @@
disabled disabled
/> />
<template v-if="status">
<NcNoteCard :type="binaryStatusType(status.perl, false)">
{{ binaryStatus("perl", status.perl) }}
</NcNoteCard>
</template>
<NcCheckboxRadioSwitch <NcCheckboxRadioSwitch
:checked.sync="exiftoolPerl" :checked.sync="exiftoolPerl"
@update:checked="update('exiftoolPerl')" @update:checked="update('exiftoolPerl')"
@ -45,6 +57,15 @@
{{ t("memories", "Enable Transcoding") }} {{ t("memories", "Enable Transcoding") }}
</NcCheckboxRadioSwitch> </NcCheckboxRadioSwitch>
<template v-if="status">
<NcNoteCard :type="binaryStatusType(status.ffmpeg)">
{{ binaryStatus("ffmpeg", status.ffmpeg) }}
</NcNoteCard>
<NcNoteCard :type="binaryStatusType(status.ffprobe)">
{{ binaryStatus("ffprobe", status.ffprobe) }}
</NcNoteCard>
</template>
<NcTextField <NcTextField
:label="t('memories', 'ffmpeg path')" :label="t('memories', 'ffmpeg path')"
:label-visible="true" :label-visible="true"
@ -102,6 +123,12 @@
{{ t("memories", "external transcoder configuration") }} {{ t("memories", "external transcoder configuration") }}
</a> </a>
<template v-if="status">
<NcNoteCard :type="binaryStatusType(status.govod)">
{{ binaryStatus("go-vod", status.govod) }}
</NcNoteCard>
</template>
<NcCheckboxRadioSwitch <NcCheckboxRadioSwitch
:checked.sync="enableExternalTranscoder" :checked.sync="enableExternalTranscoder"
@update:checked="update('enableExternalTranscoder')" @update:checked="update('enableExternalTranscoder')"
@ -178,13 +205,8 @@
VA-API configuration VA-API configuration
</a> </a>
<NcNoteCard type="warning"> <NcNoteCard :type="vaapiStatusType()" v-if="status">
{{ {{ vaapiStatusText() }}
t(
"memories",
"/dev/dri/renderD128 is required for VA-API acceleration."
)
}}
</NcNoteCard> </NcNoteCard>
<NcCheckboxRadioSwitch <NcCheckboxRadioSwitch
@ -300,6 +322,22 @@ const settings = {
/** Invert setting before saving */ /** Invert setting before saving */
const invertedBooleans = ["enableTranscoding"]; const invertedBooleans = ["enableTranscoding"];
type BinaryStatus =
| "ok"
| "not_found"
| "not_executable"
| "test_fail"
| "test_ok";
type IStatus = {
exiftool: BinaryStatus;
perl: BinaryStatus;
ffmpeg: BinaryStatus;
ffprobe: BinaryStatus;
govod: BinaryStatus;
vaapi_dev: "ok" | "not_found" | "not_readable";
};
export default defineComponent({ export default defineComponent({
name: "Admin", name: "Admin",
components: { components: {
@ -329,10 +367,13 @@ export default defineComponent({
enableNvenc: false, enableNvenc: false,
enableNvencTemporalAQ: false, enableNvencTemporalAQ: false,
nvencScaler: "", nvencScaler: "",
status: null as IStatus,
}), }),
mounted() { mounted() {
this.reload(); this.reload();
this.refreshStatus();
}, },
methods: { methods: {
@ -356,6 +397,11 @@ export default defineComponent({
this.loaded = true; this.loaded = true;
}, },
async refreshStatus() {
const res = await axios.get(API.SYSTEM_STATUS());
this.status = res.data;
},
async update(key: string, value = null) { async update(key: string, value = null) {
value ||= this[key]; value ||= this[key];
const setting = settings[key]; const setting = settings[key];
@ -374,6 +420,70 @@ export default defineComponent({
showError(this.t("memories", "Failed to update setting")); showError(this.t("memories", "Failed to update setting"));
}); });
}, },
binaryStatus(name: string, status: BinaryStatus): string {
if (status === "ok") {
return this.t("memories", "{name} binary exists and is executable", {
name,
});
} else if (status === "not_found") {
return this.t("memories", "{name} binary not found", { name });
} else if (status === "not_executable") {
return this.t("memories", "{name} binary is not executable", {
name,
});
} else if (status === "test_fail") {
return this.t("memories", "{name} binary exists but failed test", {
name,
});
} else if (status === "test_ok") {
return this.t("memories", "{name} binary exists and is usable", {
name,
});
} else {
return this.t("memories", "{name} binary status: {status}", {
name,
status,
});
}
},
binaryStatusType(status: BinaryStatus, critical = true): string {
if (status === "ok" || status === "test_ok") {
return "success";
} else if (
status === "not_found" ||
status === "not_executable" ||
status === "test_fail"
) {
return critical ? "error" : "warning";
} else {
return "warning";
}
},
vaapiStatusText(): string {
const dev = "/dev/dri/renderD128";
if (this.status.vaapi_dev === "ok") {
return this.t("memories", "VA-API device ({dev}) is readable", { dev });
} else if (this.status.vaapi_dev === "not_found") {
return this.t("memories", "VA-API device ({dev}) not found", { dev });
} else if (this.status.vaapi_dev === "not_readable") {
return this.t(
"memories",
"VA-API device ({dev}) has incorrect permissions",
{ dev }
);
} else {
return this.t("memories", "VA-API device status: {status}", {
status: this.status.vaapi_dev,
});
}
},
vaapiStatusType(): string {
return this.status.vaapi_dev === "ok" ? "success" : "error";
},
}, },
}); });
</script> </script>

View File

@ -190,6 +190,10 @@ export class API {
: gen(`${BASE}/system-config`); : gen(`${BASE}/system-config`);
} }
static SYSTEM_STATUS() {
return gen(`${BASE}/system-status`);
}
static MAP_CLUSTERS() { static MAP_CLUSTERS() {
return tok(gen(`${BASE}/map/clusters`)); return tok(gen(`${BASE}/map/clusters`));
} }