Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tags to channels #314

Draft
wants to merge 41 commits into
base: v1.9.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6df0542
Add models & migration
proof-of-reality Aug 2, 2023
fb77bad
Make `key` + `group` unique together
proof-of-reality Aug 4, 2023
c1d47d0
Add/cp initial values from localsettings to settings
proof-of-reality Aug 4, 2023
cfddb47
Merge branch 'v1.8.0' into feature/add-tags-to-channels
proof-of-reality Aug 4, 2023
88dd372
Remove LocalSettings and else conditions
proof-of-reality Aug 4, 2023
d17c813
Add groups to channels
proof-of-reality Aug 4, 2023
4fa10c2
Fix errors and switch tasks to be groups oriented
proof-of-reality Aug 4, 2023
dec1b15
Fix issue with positional arg
proof-of-reality Aug 4, 2023
37fa83f
Add groups to settings form
proof-of-reality Aug 4, 2023
3e50fba
Fix AF
proof-of-reality Aug 4, 2023
360a60b
Update models & add basic functionality
proof-of-reality Aug 6, 2023
446798c
Add groups endpoint
proof-of-reality Aug 6, 2023
d8322fe
Display tags on main tables
proof-of-reality Aug 6, 2023
72e7f7f
Add delete group
proof-of-reality Aug 6, 2023
54dab54
Add basic CRUD for groups
proof-of-reality Aug 7, 2023
71531c3
Fix handling add/rm channels to groups
proof-of-reality Aug 7, 2023
30b13b3
Fix sorting
proof-of-reality Aug 7, 2023
32dad27
Add error messages
proof-of-reality Aug 7, 2023
e1062c2
Merge branch 'v1.8.0' into feature/add-tags-to-channels
proof-of-reality Aug 7, 2023
e66142d
Add constraint for multiple groups having conflicting settings
proof-of-reality Aug 9, 2023
bf11352
Fix minimal UI settings
proof-of-reality Aug 11, 2023
444a912
Fix issue while updating default group
proof-of-reality Aug 12, 2023
af7133f
Remove return
proof-of-reality Aug 12, 2023
747e105
Fix Rebalancer
proof-of-reality Aug 13, 2023
0060275
Merge AF calculations
proof-of-reality Aug 13, 2023
bc1af0f
Fix issue with updating values & add link to conflicting field
proof-of-reality Aug 13, 2023
5a20488
Fix retrieving and updating AF settings for a channel/group
proof-of-reality Aug 13, 2023
bc94e73
Add recently discovered channel to `LNDg` defaults
proof-of-reality Aug 13, 2023
b6c9525
Exclude `LNDg` from conflicting settings
proof-of-reality Aug 13, 2023
6fe7923
Merge branch 'v1.8.0' into feature/add-tags-to-channels
proof-of-reality Aug 25, 2023
72d26e3
Fix channel creation update
proof-of-reality Oct 10, 2023
dc9d5a0
Merge branch 'v1.8.0' into feature/add-tags-to-channels
proof-of-reality Oct 10, 2023
ec90f34
Fix `update_channels` on new channel event
proof-of-reality Oct 11, 2023
77521a3
Fix test
proof-of-reality Oct 11, 2023
4945683
Fix merge issue
proof-of-reality Oct 11, 2023
0cae3a9
Fix getting AF group when AF settings is not assigned yet
proof-of-reality Oct 11, 2023
8b16c43
Merge branch 'v1.8.0' into feature/add-tags-to-channels
proof-of-reality Oct 18, 2023
046ed3b
Fixed class name
proof-of-reality Oct 18, 2023
84031a6
Merge branch 'v1.8.0' into feature/add-tags-to-channels
proof-of-reality Oct 23, 2023
b3dc6c8
Merge branch 'v1.8.0' into feature/add-tags-to-channels
proof-of-reality Oct 23, 2023
1365493
Fix rebalance scheduling
proof-of-reality Oct 23, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 12 additions & 43 deletions gui/af.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,22 @@
from pandas import DataFrame, concat
environ['DJANGO_SETTINGS_MODULE'] = 'lndg.settings'
django.setup()
from gui.models import Forwards, Channels, LocalSettings, FailedHTLCs
from gui.models import Forwards, Channels, Groups, Settings, FailedHTLCs

def main(channels):
channels_df = DataFrame.from_records(channels.values())
def main(group: Groups):
channels_df = DataFrame.from_records(group.channels.filter(is_open=True, private=False).values())
filter_1day = datetime.now() - timedelta(days=1)
filter_7day = datetime.now() - timedelta(days=7)
if channels_df.shape[0] > 0:
if LocalSettings.objects.filter(key='AF-MaxRate').exists():
max_rate = int(LocalSettings.objects.filter(key='AF-MaxRate')[0].value)
else:
LocalSettings(key='AF-MaxRate', value='2500').save()
max_rate = 2500
if LocalSettings.objects.filter(key='AF-MinRate').exists():
min_rate = int(LocalSettings.objects.filter(key='AF-MinRate')[0].value)
else:
LocalSettings(key='AF-MinRate', value='0').save()
min_rate = 0
if LocalSettings.objects.filter(key='AF-Increment').exists():
increment = int(LocalSettings.objects.filter(key='AF-Increment')[0].value)
else:
LocalSettings(key='AF-Increment', value='5').save()
increment = 5
if LocalSettings.objects.filter(key='AF-Multiplier').exists():
multiplier = int(LocalSettings.objects.filter(key='AF-Multiplier')[0].value)
else:
LocalSettings(key='AF-Multiplier', value='5').save()
multiplier = 5
if LocalSettings.objects.filter(key='AF-FailedHTLCs').exists():
failed_htlc_limit = int(LocalSettings.objects.filter(key='AF-FailedHTLCs')[0].value)
else:
LocalSettings(key='AF-FailedHTLCs', value='25').save()
failed_htlc_limit = 25
if LocalSettings.objects.filter(key='AF-UpdateHours').exists():
update_hours = int(LocalSettings.objects.filter(key='AF-UpdateHours').get().value)
else:
LocalSettings(key='AF-UpdateHours', value='24').save()
update_hours = 24
if LocalSettings.objects.filter(key='AF-LowLiqLimit').exists():
lowliq_limit = int(LocalSettings.objects.filter(key='AF-LowLiqLimit').get().value)
else:
LocalSettings(key='AF-LowLiqLimit', value='5').save()
lowliq_limit = 5
if LocalSettings.objects.filter(key='AF-ExcessLimit').exists():
excess_limit = int(LocalSettings.objects.filter(key='AF-ExcessLimit').get().value)
else:
LocalSettings(key='AF-ExcessLimit', value='95').save()
excess_limit = 95
max_rate = int(group.settings_set.filter(key='AF-MaxRate')[0].value if group.settings_set.filter(key='AF-MaxRate').exists() else Settings.objects.filter(group_id=0,key='AF-MaxRate')[0].value)
min_rate = int(group.settings_set.filter(key='AF-MinRate')[0].value if group.settings_set.filter(key='AF-MinRate').exists() else Settings.objects.filter(group_id=0,key='AF-MinRate')[0].value)
increment = int(group.settings_set.filter(key='AF-Increment')[0].value if group.settings_set.filter(key='AF-Increment').exists() else Settings.objects.filter(group_id=0,key='AF-Increment')[0].value)
multiplier = int(group.settings_set.filter(key='AF-Multiplier')[0].value if group.settings_set.filter(key='AF-Multiplier').exists() else Settings.objects.filter(group_id=0,key='AF-Multiplier')[0].value)
failed_htlc_limit = int(group.settings_set.filter(key='AF-FailedHTLCs')[0].value if group.settings_set.filter(key='AF-FailedHTLCs').exists() else Settings.objects.filter(group_id=0,key='AF-FailedHTLCs')[0].value)
update_hours = int(group.settings_set.filter(key='AF-UpdateHours').get().value if group.settings_set.filter(key='AF-UpdateHours').exists() else Settings.objects.filter(group_id=0,key='AF-UpdateHours')[0].value)
lowliq_limit = int(group.settings_set.filter(key='AF-LowLiqLimit').get().value if group.settings_set.filter(key='AF-LowLiqLimit').exists() else Settings.objects.filter(group_id=0,key='AF-LowLiqLimit')[0].value)
excess_limit = int(group.settings_set.filter(key='AF-ExcessLimit').get().value if group.settings_set.filter(key='AF-ExcessLimit').exists() else Settings.objects.filter(group_id=0,key='AF-ExcessLimit')[0].value)

if lowliq_limit >= excess_limit:
print('Invalid thresholds detected, using defaults...')
lowliq_limit = 5
Expand Down
6 changes: 4 additions & 2 deletions gui/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ class Meta:
last_hop_pubkey = forms.CharField(label='funding_txid', max_length=66, required=False)
duration = forms.IntegerField(label='duration')

class AutoRebalanceForm(forms.Form):
class AutoRebalanceForm(forms.Form):
group_id = forms.IntegerField(label="group_id", required=True)
group_name = forms.CharField(label="group_name", min_length=1, max_length=20, required=False)
enabled = forms.IntegerField(label='enabled', required=False)
target_percent = forms.FloatField(label='target_percent', required=False)
target_time = forms.IntegerField(label='target_time', required=False)
Expand Down Expand Up @@ -93,7 +95,7 @@ class GUIForm(AutoFeesForm):
gui_graphLinks = forms.CharField(label='gui_graphLinks', required=False)
gui_netLinks = forms.CharField(label='gui_netLinks', required=False)

class LocalSettingsForm(GUIForm):
class SettingsForm(GUIForm):
lnd_cleanPayments = forms.IntegerField(label='lnd_cleanPayments', required=False)
lnd_retentionDays = forms.IntegerField(label='lnd_retentionDays', required=False)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Generated by Django 4.1.5 on 2023-08-06 17:59

from django.db import migrations, models
import django.db.models.deletion

from gui.models import Groups, Channels, Settings

def migrate_update_channels(apps, schema_editor):
channels = Channels.objects.all()
lndg_default = Groups(name="", id=0) # default
lndg_default.save()
for ch in channels:
lndg_default.channels.add(ch)
lndg_default.save()

print('\nInitializing default settings...')
Settings(key='AF-MaxRate', value='2500',group=lndg_default).save()
Settings(key='AF-MinRate', value='0',group=lndg_default).save()
Settings(key='AF-Increment', value='5',group=lndg_default).save()
Settings(key='AF-Multiplier', value='5',group=lndg_default).save()
Settings(key='AF-FailedHTLCs', value='25',group=lndg_default).save()
Settings(key='AF-UpdateHours', value='24',group=lndg_default).save()
Settings(key='AF-LowLiqLimit', value='5',group=lndg_default).save()
Settings(key='AF-ExcessLimit', value='95',group=lndg_default).save()
Settings(key='AF-Enabled', value='0',group=lndg_default).save()
Settings(key='GUI-GraphLinks', value='https://amboss.space',group=lndg_default).save()
Settings(key='GUI-NetLinks', value='https://mempool.space',group=lndg_default).save()
Settings(key='LND-CleanPayments', value='0',group=lndg_default).save()
Settings(key='LND-RetentionDays', value='30',group=lndg_default).save()
Settings(key='AR-Outbound%', value='75',group=lndg_default).save()
Settings(key='AR-Inbound%', value='100',group=lndg_default).save()
Settings(key='AR-Target%', value='5',group=lndg_default).save()
Settings(key='AR-MaxCost%', value='65',group=lndg_default).save()
Settings(key='AR-Enabled', value='0',group=lndg_default).save()
Settings(key='AR-MaxFeeRate', value='100',group=lndg_default).save()
Settings(key='AR-Variance', value='0',group=lndg_default).save()
Settings(key='AR-WaitPeriod', value='30',group=lndg_default).save()
Settings(key='AR-Time', value='5',group=lndg_default).save()
Settings(key='AR-Autopilot', value='0',group=lndg_default).save()
Settings(key='AR-APDays', value='7',group=lndg_default).save()
Settings(key='AR-Workers', value='1',group=lndg_default).save()

print('\nApplying custom settings if user has any...')
for sett in apps.get_model('gui', 'localsettings').objects.all():
setting = lndg_default.settings_set.get(key=sett.key)
setting.value = sett.value
setting.save()

class Migration(migrations.Migration):

dependencies = [
('gui', '0036_peers'),
]

operations = [
migrations.CreateModel(
name='Groups',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=20, unique=True)),
('channels', models.ManyToManyField(related_name='channels_list', to='gui.channels')),
],
),
migrations.CreateModel(
name='Settings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('key', models.CharField(default=None, max_length=20)),
('value', models.CharField(default=None, max_length=50)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gui.groups')),
],
),
migrations.RunPython(migrate_update_channels, migrations.RunPython.noop),
migrations.DeleteModel(
name='LocalSettings',
)
]
48 changes: 9 additions & 39 deletions gui/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,43 +110,12 @@ class Channels(models.Model):
auto_fees = models.BooleanField()
notes = models.TextField(default='', blank=True)

def save(self, *args, **kwargs):
if self.auto_fees is None:
if LocalSettings.objects.filter(key='AF-Enabled').exists():
enabled = int(LocalSettings.objects.filter(key='AF-Enabled')[0].value)
else:
LocalSettings(key='AF-Enabled', value='0').save()
enabled = 0
self.auto_fees = False if enabled == 0 else True
if not self.ar_out_target:
if LocalSettings.objects.filter(key='AR-Outbound%').exists():
outbound_setting = int(LocalSettings.objects.filter(key='AR-Outbound%')[0].value)
else:
LocalSettings(key='AR-Outbound%', value='75').save()
outbound_setting = 75
self.ar_out_target = outbound_setting
if not self.ar_in_target:
if LocalSettings.objects.filter(key='AR-Inbound%').exists():
inbound_setting = int(LocalSettings.objects.filter(key='AR-Inbound%')[0].value)
else:
LocalSettings(key='AR-Inbound%', value='100').save()
inbound_setting = 100
self.ar_in_target = inbound_setting
if not self.ar_amt_target:
if LocalSettings.objects.filter(key='AR-Target%').exists():
amt_setting = float(LocalSettings.objects.filter(key='AR-Target%')[0].value)
else:
LocalSettings(key='AR-Target%', value='5').save()
amt_setting = 5
self.ar_amt_target = int((amt_setting/100) * self.capacity)
if not self.ar_max_cost:
if LocalSettings.objects.filter(key='AR-MaxCost%').exists():
cost_setting = int(LocalSettings.objects.filter(key='AR-MaxCost%')[0].value)
else:
LocalSettings(key='AR-MaxCost%', value='65').save()
cost_setting = 65
self.ar_max_cost = cost_setting
super(Channels, self).save(*args, **kwargs)
class Meta:
app_label = 'gui'

class Groups(models.Model):
name = models.CharField(max_length=20, unique=True)
channels = models.ManyToManyField(Channels, related_name="channels_list",)

class Meta:
app_label = 'gui'
Expand Down Expand Up @@ -181,9 +150,10 @@ class Rebalancer(models.Model):
class Meta:
app_label = 'gui'

class LocalSettings(models.Model):
key = models.CharField(primary_key=True, default=None, max_length=20)
class Settings(models.Model):
key = models.CharField(max_length=20,default=None)
value = models.CharField(default=None, max_length=50)
group = models.ForeignKey(Groups, on_delete=models.CASCADE)
class Meta:
app_label = 'gui'

Expand Down
6 changes: 3 additions & 3 deletions gui/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from rest_framework import serializers
from rest_framework.relations import PrimaryKeyRelatedField
from .models import LocalSettings, Payments, PaymentHops, Invoices, Forwards, Channels, Rebalancer, Peers, Onchain, PendingHTLCs, FailedHTLCs, Closures, Resolutions, PeerEvents
from .models import Settings, Payments, PaymentHops, Invoices, Forwards, Channels, Rebalancer, Peers, Onchain, PendingHTLCs, FailedHTLCs, Closures, Resolutions, PeerEvents

##FUTURE UPDATE 'exclude' TO 'fields'

Expand Down Expand Up @@ -170,10 +170,10 @@ class Meta:
model = PaymentHops
exclude = []

class LocalSettingsSerializer(serializers.HyperlinkedModelSerializer):
class SettingsSerializer(serializers.HyperlinkedModelSerializer):
key = serializers.ReadOnlyField()
class Meta:
model = LocalSettings
model = Settings
exclude = []

class PendingHTLCSerializer(serializers.HyperlinkedModelSerializer):
Expand Down
4 changes: 2 additions & 2 deletions gui/static/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ async function DELETE(url, {method = 'DELETE'} = {}){
}

async function call({url, method, data, body, headers = {'Content-Type':'application/json'}}){
if(url.charAt(url.length-1) != '/') url += '/'
if(!url.endsWith('/')) url += '/'
if(method != 'GET') headers['X-CSRFToken'] = document.getElementById('api').dataset.token
const result = await fetch(`api/${url}${data ? '?': ''}${new URLSearchParams(data).toString()}`, {method, body: JSON.stringify(body), headers})
const result = await fetch(`${window.location.origin}/api/${url}${data ? '?': ''}${new URLSearchParams(data).toString()}`, {method, body: JSON.stringify(body), headers})
return result.json()
}

Expand Down
12 changes: 6 additions & 6 deletions gui/static/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ async function toggle(button){
}
function use(template){
return {
render: function(object, id='id', row = null){
render: function(object, id='id', columnType = "td", row = undefined){
const tr = row ?? document.createElement("tr")
tr.objId = object[id]
for (key in template){
const transforms = template[key](object)
const td = document.createElement("td")
td.setAttribute('name', key)
td.render(transforms)
tr.append(td)
const transforms = template[key](object, key)
const col = document.createElement(columnType)
col.setAttribute('name', key)
col.render(transforms)
tr.append(col)
}
return tr
}
Expand Down
7 changes: 2 additions & 5 deletions gui/templates/advanced.html
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,10 @@ <h2>Advanced Channel Settings</h2>
</table>
</div>
</div>
{% endif %}
{% if not channels %}
{% else %}
<div class="w3-container w3-padding-small">
<center><h1>You dont have any channels to setup yet!</h1></center>
</div>
{% endif %}
{% if local_settings %}
{% include 'local_settings.html' with settings=local_settings title='Update Local' %}
{% endif %}
{% include 'settings.html' with configs="'AF-,AR-,GUI-,LND-'" title='Update' %}
{% endblock %}
2 changes: 1 addition & 1 deletion gui/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
{% for message in messages %}
<div class="w3-panel w3-orange w3-display-container w3-padding">
<span onclick="this.parentElement.style.display='none'" class="w3-button w3-hover-red w3-display-topright">X</span>
<h1 style="word-wrap:break-word">{{ message.message }}</h1>
<h1 style="word-wrap:break-word">{{ message.message |safe }}</h1>
proof-of-reality marked this conversation as resolved.
Show resolved Hide resolved
{% with sliced_msg=message.message|slice:":17" %}
{% if sliced_msg == "Deposit Address: " or sliced_msg == "Invoice created! " %}
{% qr_from_text message.message|slice:"17:" size="s" image_format="png" error_correction="L" %}
Expand Down
4 changes: 1 addition & 3 deletions gui/templates/fee_rates.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,5 @@ <h2>Suggested Fee Rates</h2>
<center><h1>You dont have any channels to analyze yet!</h1></center>
</div>
{% endif %}
{% if local_settings %}
{% include 'local_settings.html' with settings=local_settings title='Auto-Fees' postURL='update_setting' %}
{% endif %}
{% include 'settings.html' with configs="'AF-'" title='Auto-Fees' postURL='update_setting' %}
{% endblock %}
2 changes: 1 addition & 1 deletion gui/templates/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ <h6 style="display: none" id="private_stats">
</tfoot>
</table>
</div>
{% include 'local_settings.html' with settings=local_settings title="Auto-Rebalancer" url='rebalancing' %}
{% include 'settings.html' with configs="'AR-'" title="Auto-Rebalancer" url='rebalancing' %}
<div class="w3-container w3-padding-small">
<h2>Connect to a Peer</h2>
<div class="w3-container w3-padding-small">
Expand Down
34 changes: 0 additions & 34 deletions gui/templates/local_settings.html

This file was deleted.

2 changes: 1 addition & 1 deletion gui/templates/rebalancing.html
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,5 @@ <h5 style="float:left" title="Select outgoing channels above">Manual Rebalance R
}
</script>
{% include 'rebalances_table.html' with count=20 load_count=10 title='<a href="/rebalances" target="_blank">Rebalance Requests</a>' %}
{% include 'local_settings.html' with settings=local_settings title='Auto-Rebalancer' %}
{% include 'settings.html' with settings=local_settings title='Auto-Rebalancer' %}
{% endblock %}
Loading