diff --git a/config.go b/config.go index c68adb6..7718cef 100644 --- a/config.go +++ b/config.go @@ -28,6 +28,7 @@ type Config struct { } type Device struct { + ID string Name string Address string Port int @@ -48,10 +49,9 @@ func readConfig() (config Config, err error) { return } -func (cfg *Config) UpdateDevice(currentName string, deviceToUpdate Device) (dev Device, err error) {// {{{ - +func (cfg *Config) UpdateDevice(deviceToUpdate Device) (dev Device, err error) { // {{{ i := slices.IndexFunc(cfg.Devices, func(d Device) bool { - return strings.TrimSpace(strings.ToLower(d.Name)) == strings.TrimSpace(strings.ToLower(currentName)) + return d.ID == deviceToUpdate.ID }) if i > -1 { @@ -75,7 +75,7 @@ func (cfg *Config) UpdateDevice(currentName string, deviceToUpdate Device) (dev return } - dev.Name = strings.TrimSpace(strings.ToLower(deviceToUpdate.Name)) + dev.Name = strings.TrimSpace(deviceToUpdate.Name) dev.Address = strings.TrimSpace(strings.ToLower(deviceToUpdate.Address)) dev.Port = deviceToUpdate.Port dev.Username = strings.TrimSpace(deviceToUpdate.Username) @@ -91,6 +91,7 @@ func (cfg *Config) UpdateDevice(currentName string, deviceToUpdate Device) (dev err = fmt.Errorf("Password can't be empty") return } + dev.ID = deviceToUpdate.ID dev.Password = strings.TrimSpace(deviceToUpdate.Password) cfg.Devices = append(cfg.Devices, dev) } else { @@ -104,14 +105,14 @@ func (cfg *Config) UpdateDevice(currentName string, deviceToUpdate Device) (dev err = os.WriteFile(cfg.filename, j, 0600) return -}// }}} -func (cfg *Config) DeleteDevice(devname string) (err error) {// {{{ +} // }}} +func (cfg *Config) DeleteDevice(devID string) (err error) { // {{{ cfg.Devices = slices.DeleteFunc(cfg.Devices, func(d Device) bool { - return strings.TrimSpace(strings.ToLower(d.Name)) == strings.TrimSpace(strings.ToLower(devname)) + return d.ID == devID }) j, _ := json.Marshal(cfg) err = os.WriteFile(cfg.filename, j, 0600) return -}// }}} +} // }}} diff --git a/main.go b/main.go index 6be7b38..d978b50 100644 --- a/main.go +++ b/main.go @@ -6,11 +6,11 @@ import ( // Standard "flag" + "fmt" "log/slog" "os" "path" "slices" - "fmt" ) const VERSION = "v1" @@ -77,35 +77,35 @@ func main() { devices = make(map[string]RouterosDevice) /* - device.Host = config.Device.Address - device.Port = config.Device.Port - device.Username = config.Device.Username - device.Password = config.Device.Password - device.Timeout = config.Device.Timeout - device.Init() + device.Host = config.Device.Address + device.Port = config.Device.Port + device.Username = config.Device.Username + device.Password = config.Device.Password + device.Timeout = config.Device.Timeout + device.Init() */ registerWebserverHandlers() startWebserver() } -func routerosDevice(name string) (dev RouterosDevice, err error) { +func routerosDevice(id string) (dev RouterosDevice, err error) { var found bool - if dev, found = devices[name]; found { - logger.Debug("routeros", "op", "connection", "name", name, "cached", true) + if dev, found = devices[id]; found { + logger.Debug("routeros", "op", "connection", "ID", id, "cached", true) return } i := slices.IndexFunc(config.Devices, func(d Device) bool { - return d.Name == name + return d.ID == id }) if i == -1 { - err = fmt.Errorf("Unknown device '%s'", name) + err = fmt.Errorf("Unknown device '%s'", id) logger.Error("routeros", "op", "connection", "error", err) return } - logger.Debug("routeros", "name", name, "cached", false) + logger.Debug("routeros", "name", id, "cached", false) confDev := config.Devices[i] dev.Host = confDev.Address dev.Port = confDev.Port @@ -113,7 +113,7 @@ func routerosDevice(name string) (dev RouterosDevice, err error) { dev.Password = confDev.Password dev.Timeout = confDev.Timeout dev.Init() - devices[name] = dev + devices[id] = dev return } diff --git a/static/js/dns.mjs b/static/js/dns.mjs index cc74be1..8a7dd93 100644 --- a/static/js/dns.mjs +++ b/static/js/dns.mjs @@ -25,8 +25,8 @@ export class Application { alert(err) }) - _mbus.subscribe('device_selected', event => this.connectDevice(event.detail.devName)) - _mbus.subscribe('device_deleted', event => this.deleteDevice(event.detail.devName)) + _mbus.subscribe('device_selected', event => this.connectDevice(event.detail.devID)) + _mbus.subscribe('device_deleted', event => this.deleteDevice(event.detail.devID)) _mbus.subscribe('search', () => this.search()) }// }}} @@ -34,8 +34,6 @@ export class Application { resetDeviceState() {// {{{ if (this.recordsTree) { this.recordsTree.remove() - this.recordsTree = null - return } this.topFolder = new Folder(this, null, 'root') @@ -60,7 +58,7 @@ export class Application { this.devices = new Map() for (const devData of json.Devices) { const dev = new Device(devData) - this.devices.set(dev.name(), dev) + this.devices.set(dev.id(), dev) } resolve() @@ -69,17 +67,18 @@ export class Application { }// }}} // connectDevice resets the device state, retrieves the records and renders everything necessary. - async connectDevice(devName) {// {{{ + async connectDevice(devID) {// {{{ this.resetDeviceState() - if (devName == '-') { + + if (devID == '-') { this.settings.set('last_device', '') return } try { - const dev = this.devices.get(devName) + const dev = this.devices.get(devID) if (dev === undefined) { - alert(`Unknown device '${devName}'`) + alert(`Unknown device '${devID}'`) return } this.currentDevice = dev @@ -87,7 +86,7 @@ export class Application { const records = await this.currentDevice.retrieveRecords() this.records = this.parseRecords(records) - this.settings.set('last_device', this.currentDevice.name()) + this.settings.set('last_device', this.currentDevice.id()) this.createFolders() this.renderDevice() @@ -98,9 +97,9 @@ export class Application { }// }}} // deleteDevice removes it from the list and resets app state if it was connected. - deleteDevice(devName) {// {{{ - this.devices.delete(devName) - if (this.currentDevice?.name() == devName) { + deleteDevice(devID) {// {{{ + this.devices.delete(devID) + if (this.currentDevice?.id() == devID) { this.resetDeviceState() this.settings.set('last_device', '') } @@ -396,8 +395,11 @@ class Device { constructor(data) {// {{{ this.data = data }// }}} + id() {// {{{ + return this.data.ID || '' + }// }}} name() {// {{{ - return this.data.Name?.toLowerCase() || '' + return this.data.Name || '' }// }}} address() {// {{{ return this.data.Address || '' @@ -411,11 +413,8 @@ class Device { password() {// {{{ return this.data.Password || '' }// }}} - name() {// {{{ - return this.data.Name?.toLowerCase() || '' - }// }}} async retrieveRecords() {// {{{ - const data = await fetch(`/device/${this.name()}/dns_records`) + const data = await fetch(`/device/${this.id()}/dns_records`) const json = await data.json() if (!json.OK) throw new Error(json.Error) @@ -431,7 +430,7 @@ class DeviceSelectWidget { this.elDeviceSelect = null this.currentlySelected = null - _mbus.subscribe('device_deleted', event => this.deleteDevice(event.detail.devName)) + _mbus.subscribe('device_deleted', event => this.deleteDevice(event.detail.devID)) _mbus.subscribe('device_updated', event => this.updateDevice(event.detail.device)) }// }}} setDevices(devices) {// {{{ @@ -461,12 +460,16 @@ class DeviceSelectWidget { emptyOption.dataset.devicename = "-" this.elDeviceSelect.appendChild(emptyOption) - const devNames = Array.from(this.devices.keys()).sort() - devNames.forEach(devName => { - const dev = this.devices.get(devName) + const devs = Array.from(this.devices.values()).sort((a, b) => { + if (a.name().toLowerCase() < b.name().toLowerCase()) return -1 + if (a.name().toLowerCase() > b.name().toLowerCase()) return 1 + return 0 + }) + devs.forEach(dev => { const option = document.createElement('option') + option.value = dev.id() option.innerText = dev.name() - option.dataset.devicename = dev.name() + option.dataset.id = dev.id() this.elDeviceSelect.appendChild(option) }) @@ -474,21 +477,20 @@ class DeviceSelectWidget { this.elDeviceSelect.value = this.currentlySelected }// }}} notifyDeviceSelect() {// {{{ - const devName = this.elDeviceSelect.value - this.currentlySelected = devName - _mbus.dispatch('device_selected', { devName }) + const devID = this.elDeviceSelect.value + this.currentlySelected = devID + _mbus.dispatch('device_selected', { devID }) }// }}} - selectDevice(devname) {// {{{ - this.elDeviceSelect.value = devname + selectDevice(devID) {// {{{ + this.elDeviceSelect.value = devID this.notifyDeviceSelect() }// }}} - deleteDevice(devName) {// {{{ - this.devices.delete(devName) + deleteDevice(devID) {// {{{ + this.devices.delete(devID) this.restockDeviceSelect() }// }}} updateDevice(dev) {// {{{ - console.log(dev) - this.devices.set(dev.name(), dev) + this.devices.set(dev.id(), dev) this.restockDeviceSelect() }// }}} } @@ -686,8 +688,6 @@ class Record { labels.reverse() labels = [`${labels[1]}.${labels[0]}`].concat(labels.slice(2)) labels.reverse() - } else { - console.log(this, labels) } return labels @@ -817,7 +817,7 @@ class Record { save() {// {{{ const created = (this.id() == '') - fetch(`/device/${_app.currentDevice.name()}/record`, { + fetch(`/device/${_app.currentDevice.id()}/record`, { method: 'POST', body: JSON.stringify(this.data), }) @@ -855,7 +855,7 @@ class Record { if (!confirm(`Are you sure you want to delete ${this.name()}?`)) return - fetch(`/device/${_app.currentDevice.name()}/record/${this.id()}`, { method: 'DELETE' }) + fetch(`/device/${_app.currentDevice.id()}/record/${this.id()}`, { method: 'DELETE' }) .then(data => data.json()) .then(json => { if (!json.OK) { @@ -1091,7 +1091,7 @@ class DeviceDialog { filterDevices() {// {{{ const filter = this.dlg.querySelector('.filter').value.toLowerCase() - this.elDeviceList.querySelectorAll('.device').forEach(dev=>{ + this.elDeviceList.querySelectorAll('.device').forEach(dev => { if (dev.innerText.toLowerCase().includes(filter)) dev.classList.remove('filtered') else @@ -1110,17 +1110,18 @@ class DeviceDialog { devices.forEach(dev => { const devEl = document.createElement('div') devEl.classList.add('device') - devEl.dataset.name = dev.name() + devEl.dataset.id = dev.id() devEl.innerText = dev.name() - devEl.addEventListener('click', () => this.editDevice(dev, devEl)) + devEl.addEventListener('click', () => this.editDevice(dev)) this.elDeviceList.appendChild(devEl) }) }// }}} - editDevice(dev, devEl) {// {{{ + editDevice(dev) {// {{{ this.device = dev this.elDevices.querySelectorAll('.device.selected').forEach(el => el.classList.remove('selected')) + const devEl = this.elDeviceList.querySelector(`[data-id="${dev.id()}"]`) devEl.classList.add('selected') this.elName.value = dev.name() @@ -1133,7 +1134,7 @@ class DeviceDialog { let name = prompt('Name of new device') if (name === null || name.trim() === '') return - name = name.trim().toLowerCase() + name = name.trim() // Make sure it doesn't already exist. if (this.devices.has(name)) { @@ -1141,18 +1142,20 @@ class DeviceDialog { return } - const dev = new Device({Name: name, Port: 443}, true) + const dev = new Device({ + ID: crypto.randomUUID(), + Name: name, + Port: 443 + }, true) - this.devices.set(name, dev) + this.devices.set(dev.id(), dev) this.updateDeviceList() - - const devEl = this.elDeviceList.querySelector(`[data-name="${dev.name()}"]`) - this.editDevice(dev, devEl) + this.editDevice(dev) }// }}} async updateDevice() {// {{{ const req = { - CurrentName: this.device.name(), Device: { + ID: this.device.id(), Name: this.elName.value, Address: this.elAddress.value, Port: parseInt(this.elPort.value), @@ -1186,12 +1189,13 @@ class DeviceDialog { } }// }}} async deleteDevice() {// {{{ + const devID = this.device.id() const devname = this.device.name() if (!confirm(`Do you want to delete '${devname}'?`)) return try { - const data = await fetch(`/device/${devname}`, { method: 'DELETE' }) + const data = await fetch(`/device/${devID}`, { method: 'DELETE' }) const json = await data.json() if (!json.OK) { alert(json.Error) @@ -1204,10 +1208,10 @@ class DeviceDialog { this.elUsername.value = '' this.elPassword.value = '' - this.devices.delete(devname) + this.devices.delete(devID) this.device = null this.updateDeviceList() - _mbus.dispatch('device_deleted', { devName: devname }) + _mbus.dispatch('device_deleted', { devID: devID }) } catch (err) { console.error(err) alert(err) diff --git a/webserver.go b/webserver.go index bd3de42..e2746d1 100644 --- a/webserver.go +++ b/webserver.go @@ -100,8 +100,7 @@ func actionDevices(w http.ResponseWriter, r *http.Request) { // {{{ } // }}} func actionDeviceUpdate(w http.ResponseWriter, r *http.Request) { // {{{ var req struct { - CurrentName string - Device Device + Device Device } body, _ := io.ReadAll(r.Body) @@ -111,7 +110,7 @@ func actionDeviceUpdate(w http.ResponseWriter, r *http.Request) { // {{{ return } - device, err := config.UpdateDevice(req.CurrentName, req.Device) + device, err := config.UpdateDevice(req.Device) if err != nil { httpError(w, err) return @@ -128,9 +127,9 @@ func actionDeviceUpdate(w http.ResponseWriter, r *http.Request) { // {{{ w.Write(j) } // }}} func actionDeviceDelete(w http.ResponseWriter, r *http.Request) { // {{{ - devname := r.PathValue("dev") + devID := r.PathValue("dev") - err := config.DeleteDevice(devname) + err := config.DeleteDevice(devID) if err != nil { httpError(w, err) return @@ -141,9 +140,9 @@ func actionDeviceDelete(w http.ResponseWriter, r *http.Request) { // {{{ } // }}} func actionDNSRecords(w http.ResponseWriter, r *http.Request) { // {{{ - devname := r.PathValue("dev") + devID := r.PathValue("dev") - device, err := routerosDevice(devname) + device, err := routerosDevice(devID) if err != nil { httpError(w, err) return