-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add LuCI interface for the AList package. Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
- Loading branch information
1 parent
d5db173
commit f0c6def
Showing
5 changed files
with
276 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# Copyright (C) 2023 ImmortalWrt.org | ||
|
||
include $(TOPDIR)/rules.mk | ||
|
||
LUCI_TITLE:=LuCI app for AList | ||
LUCI_DEPENDS:=+alist | ||
|
||
include ../../luci.mk | ||
|
||
# call BuildPackage - OpenWrt buildroot signature |
144 changes: 144 additions & 0 deletions
144
applications/luci-app-alist/htdocs/luci-static/resources/view/alist/config.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
'use strict'; | ||
'require form'; | ||
'require poll'; | ||
'require rpc'; | ||
'require uci'; | ||
'require validation'; | ||
'require view'; | ||
|
||
var callServiceList = rpc.declare({ | ||
object: 'service', | ||
method: 'list', | ||
params: ['name'], | ||
expect: { '': {} } | ||
}); | ||
|
||
function getServiceStatus() { | ||
return L.resolveDefault(callServiceList('alist'), {}).then(function (res) { | ||
var isRunning = false; | ||
try { | ||
isRunning = res['alist']['instances']['instance1']['running']; | ||
} catch (e) { } | ||
return isRunning; | ||
}); | ||
} | ||
|
||
function renderStatus(isRunning, port) { | ||
var spanTemp = '<span style="color:%s"><strong>%s %s</strong></span>'; | ||
var renderHTML; | ||
if (isRunning) { | ||
var button = String.format(' <a class="btn cbi-button" href="http://%s:%s" target="_blank" rel="noreferrer noopener">%s</a>', | ||
window.location.hostname, port, _('Open Web Interface')); | ||
renderHTML = spanTemp.format('green', _('AList'), _('RUNNING')) + button; | ||
} else { | ||
renderHTML = spanTemp.format('red', _('AList'), _('NOT RUNNING')); | ||
} | ||
|
||
return renderHTML; | ||
} | ||
|
||
var stubValidator = { | ||
factory: validation, | ||
apply: function(type, value, args) { | ||
if (value != null) | ||
this.value = value; | ||
|
||
return validation.types[type].apply(this, args); | ||
}, | ||
assert: function(condition) { | ||
return !!condition; | ||
} | ||
}; | ||
|
||
return view.extend({ | ||
load: function() { | ||
return Promise.all([ | ||
uci.load('alist') | ||
]); | ||
}, | ||
|
||
render: function(data) { | ||
var m, s, o; | ||
var webport = uci.get(data[0], 'config', 'listen_http_port') || '5244'; | ||
|
||
m = new form.Map('alist', _('AList'), | ||
_('A file list/WebDAV program that supports multiple storages, powered by Gin and Solidjs.') + '<br />' + | ||
_('Default webUI/WebDAV login username is %s and password is %s.').format('<code>admin</code>', '<code>password</code>')); | ||
|
||
s = m.section(form.TypedSection); | ||
s.anonymous = true; | ||
s.render = function () { | ||
poll.add(function () { | ||
return L.resolveDefault(getServiceStatus()).then(function (res) { | ||
var view = document.getElementById('service_status'); | ||
view.innerHTML = renderStatus(res, webport); | ||
}); | ||
}); | ||
|
||
return E('div', { class: 'cbi-section', id: 'status_bar' }, [ | ||
E('p', { id: 'service_status' }, _('Collecting data...')) | ||
]); | ||
} | ||
|
||
s = m.section(form.NamedSection, 'config', 'alist'); | ||
|
||
o = s.option(form.Flag, 'enabled', _('Enable')); | ||
o.default = o.disabled; | ||
o.rmempty = false; | ||
|
||
o = s.option(form.Value, 'listen_addr', _('Listen address')); | ||
o.placeholder = '0.0.0.0'; | ||
o.validate = function(section_id, value) { | ||
if (section_id && value) { | ||
var m4 = value.match(/^([^\[\]:]+)$/), | ||
m6 = value.match(/^\[(.+)\]$/ ); | ||
|
||
if ((!m4 && !m6) || !stubValidator.apply('ipaddr', m4 ? m4[1] : m6[1])) | ||
return _('Expecting: %s').format(_('valid IP address')); | ||
} | ||
return true; | ||
} | ||
|
||
o = s.option(form.Value, 'listen_http_port', _('Listen port')); | ||
o.datatype = 'port'; | ||
o.placeholder = '5244'; | ||
|
||
o = s.option(form.Value, 'site_login_expire', _('Login expiration time'), | ||
_('User login expiration time (in hours).')); | ||
o.datatype = 'uinteger'; | ||
o.placeholder = '48'; | ||
|
||
o = s.option(form.Value, 'site_max_connections', _('Max connections'), | ||
_('The maximum number of concurrent connections at the same time (0 = unlimited).')); | ||
o.datatype = 'uinteger'; | ||
o.placeholder = '0'; | ||
|
||
o = s.option(form.Flag, 'site_tls_insecure', _('Allow insecure connection'), | ||
_('Allow connection even if the remote TLS certificate is invalid (<strong>not recommended</strong>).')); | ||
|
||
o = s.option(form.Flag, 'log_enable', _('Enable logging')); | ||
o.default = o.enabled; | ||
|
||
o = s.option(form.Value, 'log_max_size', _('Max log size'), | ||
_('The maximum size in megabytes of the log file before it gets rotated.')); | ||
o.datatype = 'uinteger'; | ||
o.placeholder = '5'; | ||
o.depends('log_enable', '1'); | ||
|
||
o = s.option(form.Value, 'log_max_backups', _('Max log backups'), | ||
_('The maximum number of old log files to retain.')); | ||
o.datatype = 'uinteger'; | ||
o.placeholder = '1'; | ||
o.depends('log_enable', '1'); | ||
|
||
o = s.option(form.Value, 'log_max_age', _('Max log age'), | ||
_('The maximum days of the log file to retain.')); | ||
o.datatype = 'uinteger'; | ||
o.placeholder = '15'; | ||
o.depends('log_enable', '1'); | ||
|
||
return m.render(); | ||
} | ||
}); |
75 changes: 75 additions & 0 deletions
75
applications/luci-app-alist/htdocs/luci-static/resources/view/alist/log.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
'use strict'; | ||
'require dom'; | ||
'require fs'; | ||
'require poll'; | ||
'require uci'; | ||
'require view'; | ||
|
||
return view.extend({ | ||
render: function() { | ||
/* Thanks to luci-app-aria2 */ | ||
var css = ' \ | ||
#log_textarea { \ | ||
padding: 10px; \ | ||
text-align: left; \ | ||
} \ | ||
#log_textarea pre { \ | ||
padding: .5rem; \ | ||
word-break: break-all; \ | ||
margin: 0; \ | ||
} \ | ||
.description { \ | ||
background-color: #33ccff; \ | ||
}'; | ||
|
||
var log_textarea = E('div', { 'id': 'log_textarea' }, | ||
E('img', { | ||
'src': L.resource(['icons/loading.gif']), | ||
'alt': _('Loading...'), | ||
'style': 'vertical-align:middle' | ||
}, _('Collecting data...')) | ||
); | ||
|
||
poll.add(L.bind(function() { | ||
return fs.read_direct('/var/run/alist/log/alist.log', 'text') | ||
.then(function(res) { | ||
var log = E('pre', { 'wrap': 'pre' }, [ | ||
res.trim() || _('Log is empty.') | ||
]); | ||
|
||
dom.content(log_textarea, log); | ||
}).catch(function(err) { | ||
var log; | ||
|
||
if (err.toString().includes('NotFoundError')) | ||
log = E('pre', { 'wrap': 'pre' }, [ | ||
_('Log file does not exist.') | ||
]); | ||
else | ||
log = E('pre', { 'wrap': 'pre' }, [ | ||
_('Unknown error: %s').format(err) | ||
]); | ||
|
||
dom.content(log_textarea, log); | ||
}); | ||
})); | ||
|
||
return E([ | ||
E('style', [ css ]), | ||
E('div', {'class': 'cbi-map'}, [ | ||
E('div', {'class': 'cbi-section'}, [ | ||
log_textarea, | ||
E('div', {'style': 'text-align:right'}, | ||
E('small', {}, _('Refresh every %s seconds.').format(L.env.pollinterval)) | ||
) | ||
]) | ||
]) | ||
]); | ||
}, | ||
|
||
handleSaveApply: null, | ||
handleSave: null, | ||
handleReset: null | ||
}); |
28 changes: 28 additions & 0 deletions
28
applications/luci-app-alist/root/usr/share/luci/menu.d/luci-app-alist.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
{ | ||
"admin/services/alist": { | ||
"title": "AList", | ||
"action": { | ||
"type": "firstchild" | ||
}, | ||
"depends": { | ||
"acl": [ "luci-app-alist" ], | ||
"uci": { "alist": true } | ||
} | ||
}, | ||
"admin/services/alist/config": { | ||
"title": "Settings", | ||
"order": 10, | ||
"action": { | ||
"type": "view", | ||
"path": "alist/config" | ||
} | ||
}, | ||
"admin/services/alist/log": { | ||
"title": "Log", | ||
"order": 20, | ||
"action": { | ||
"type": "view", | ||
"path": "alist/log" | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
applications/luci-app-alist/root/usr/share/rpcd/acl.d/luci-app-alist.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"luci-app-alist": { | ||
"description": "Grant UCI access for luci-app-alist", | ||
"read": { | ||
"file": { | ||
"/var/run/alist/log/alist.log": [ "read" ] | ||
}, | ||
"ubus": { | ||
"service": [ "list" ] | ||
}, | ||
"uci": [ "alist" ] | ||
}, | ||
"write": { | ||
"uci": [ "alist" ] | ||
} | ||
} | ||
} |