Merge branch 'master' of https://code.hackerspace.pl/q3k/bitvend into usb-interface
commit
f4f76f888e
|
@ -6,3 +6,4 @@
|
|||
cython-tests/*
|
||||
.ropeproject
|
||||
cygpio/*
|
||||
result
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
graft bitvend/static
|
||||
graft bitvend/templates
|
||||
global-exclude *.pyc
|
|
@ -1,3 +1,5 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import logging
|
||||
|
||||
logging.basicConfig(level=logging.INFO) # noqa
|
|
@ -30,6 +30,7 @@ def bitvend_user_loader(username, profile=None):
|
|||
def create_app():
|
||||
app = flask.Flask(__name__)
|
||||
app.config.from_object('bitvend.default_settings')
|
||||
print('Loading extra settings from {}...'.format(os.environ.get('BITVEND_SETTINGS', '')))
|
||||
app.config.from_pyfile(os.environ.get('BITVEND_SETTINGS', ''), silent=True)
|
||||
|
||||
# Use proper proxy headers, this fixes invalid scheme in
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from flask import Blueprint, render_template, redirect, request, flash, url_for
|
||||
from flask_login import current_user, fresh_login_required
|
||||
|
||||
from bitvend import dev
|
||||
from bitvend.models import db, Transaction
|
||||
from bitvend.forms import ManualForm
|
||||
from spaceauth import cap_required
|
||||
|
@ -31,3 +32,21 @@ def transactions(page):
|
|||
return render_template('admin/transactions.html',
|
||||
transactions=Transaction.query.paginate(page)
|
||||
)
|
||||
|
||||
|
||||
@bp.route('/begin')
|
||||
@fresh_login_required
|
||||
@admin_required
|
||||
def begin():
|
||||
dev.begin_session(500)
|
||||
flash('Operation successful.', 'success')
|
||||
return redirect('/')
|
||||
|
||||
|
||||
@bp.route('/cancel')
|
||||
@fresh_login_required
|
||||
@admin_required
|
||||
def cancel():
|
||||
dev.cancel_session()
|
||||
flash('Operation successful.', 'success')
|
||||
return redirect('/')
|
||||
|
|
|
@ -42,4 +42,4 @@ ITEMS = [
|
|||
},
|
||||
]
|
||||
|
||||
DEBT_LIMIT = 2500
|
||||
DEBT_LIMIT = 1500
|
||||
|
|
|
@ -45,5 +45,4 @@ class TransferForm(FlaskForm):
|
|||
|
||||
class ManualForm(FlaskForm):
|
||||
amount = DecimalUnityField("Amount", default=0, validators=[
|
||||
NumberRange(min=1),
|
||||
])
|
||||
|
|
|
@ -77,10 +77,10 @@
|
|||
{% endif %}
|
||||
|
||||
<p class="navbar-text navbar-right">
|
||||
1zł = {{ format_btc(from_local_currency(100)) }}
|
||||
1zł = {{ format_btc(from_local_currency(100, True)) }}
|
||||
</p>
|
||||
<p class="navbar-text navbar-right">
|
||||
<b>Rate:</b> {{ to_local_currency(100000000) / 100 }}zł
|
||||
<b>Rate:</b> {{ to_local_currency(100000000, True) / 100 }}zł
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
|
|
@ -53,8 +53,8 @@
|
|||
<thead><tr>
|
||||
<th>Name</th><th class="text-right">Balance</th>
|
||||
</tr></thead>
|
||||
{% for user in hallofshame %}
|
||||
<tr><td>{{ user }}</td><td class="text-right">{{ format_currency(user.balance) }}</td></tr>
|
||||
{% for user, balance in hallofshame %}
|
||||
<tr><td>{{ user }}</td><td class="text-right">{{ format_currency(balance) }}</td></tr>
|
||||
{% else %}
|
||||
<tr><td colspan=2 class="placeholder">Wow! Nobody's due!</td></tr>
|
||||
{% endfor %}
|
||||
|
@ -65,8 +65,8 @@
|
|||
<thead><tr>
|
||||
<th>Name</th><th class="text-right">Amount</th><th>Purchases</th>
|
||||
</tr></thead>
|
||||
{% for user in hallofaddicts %}
|
||||
<tr><td>{{ user }}</td><td class="text-right">{{ format_currency(user.purchase_amount) }}</td><td>{{ user.purchase_count }}</td></tr>
|
||||
{% for user, purchase_amount, purchase_count in hallofaddicts %}
|
||||
<tr><td>{{ user }}</td><td class="text-right">{{ format_currency(purchase_amount) }}</td><td>{{ purchase_count }}</td></tr>
|
||||
{% else %}
|
||||
<tr><td colspan=3 class="placeholder">Huh?</td></tr>
|
||||
{% endfor %}
|
||||
|
@ -132,7 +132,7 @@
|
|||
<div class="col-md-12">
|
||||
<div class="pull-right">
|
||||
<span class="label label-info">{{ format_currency(item.value) }}</span>
|
||||
<span class="label label-primary">{{ format_btc(from_local_currency(item.value*1.03)) }}</span>
|
||||
<span class="label label-primary">{{ format_btc(from_local_currency(item.value*1.03, True)) }}</span>
|
||||
</div>
|
||||
<h3>{{ item.name }}</h3>
|
||||
</div>
|
||||
|
@ -140,7 +140,7 @@
|
|||
<img src="{{ item.image }}" class="img-responsive center-block" />
|
||||
</div>
|
||||
<div class="col-xs-6 text-center">
|
||||
{% with btc_uri = 'bitcoin:%s?amount=%s' % (config['INPUT_ADDRESS'], sat_to_btc(from_local_currency(item.value*1.03))) %}
|
||||
{% with btc_uri = 'bitcoin:%s?amount=%s' % (config['INPUT_ADDRESS'], sat_to_btc(from_local_currency(item.value*1.03, True))) %}
|
||||
<a href="{{ btc_uri }}">
|
||||
<img src="{{ qrcode(btc_uri) }}" class="img-responsive center-block"/>
|
||||
<code><small>{{ config['INPUT_ADDRESS'] }}</small></code>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import cachetools
|
||||
import requests
|
||||
|
||||
|
@ -6,14 +8,25 @@ def get_exchange_rate(currency='PLN'):
|
|||
# Returns current exchange rate for selected currency
|
||||
return requests.get('https://blockchain.info/pl/ticker').json()[currency]['last']
|
||||
|
||||
def to_local_currency(sat):
|
||||
def to_local_currency(sat, safe=False):
|
||||
# Returns satoshi in local lowest denomination currency (grosze)
|
||||
try:
|
||||
rate = get_exchange_rate()
|
||||
except:
|
||||
if safe:
|
||||
return 0
|
||||
raise
|
||||
return int(sat / 1000000.0 * rate)
|
||||
|
||||
def from_local_currency(val):
|
||||
def from_local_currency(val, safe=False):
|
||||
# Returns satoshi value from local currency
|
||||
try:
|
||||
rate = get_exchange_rate()
|
||||
except:
|
||||
if safe:
|
||||
return 0
|
||||
raise
|
||||
|
||||
return int(val / rate * 1000000)
|
||||
|
||||
def sat_to_btc(amount):
|
||||
|
|
|
@ -19,12 +19,14 @@ bp = Blueprint('bitvend', __name__, template_folder='templates')
|
|||
def index():
|
||||
transactions = []
|
||||
hallofshame = User.query \
|
||||
.with_entities(User, User.balance) \
|
||||
.order_by(User.balance.asc()) \
|
||||
.filter(User.balance < 0) \
|
||||
.limit(5) \
|
||||
.all()
|
||||
|
||||
hallofaddicts = User.query \
|
||||
.with_entities(User, User.purchase_amount, User.purchase_count) \
|
||||
.order_by(User.purchase_amount.desc()) \
|
||||
.filter(User.purchase_amount > 0) \
|
||||
.limit(5) \
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
RX_PIN = 4
|
||||
TX_PIN = 17
|
||||
|
||||
cdef extern from "pigpio.h":
|
||||
int gpioInitialise()
|
||||
int gpioCfgInterfaces(unsigned ifFlags)
|
||||
|
||||
int gpioSetMode(unsigned gpio, unsigned mode)
|
||||
|
||||
int gpioSerialReadOpen(unsigned user_gpio, unsigned baud, unsigned data_bits)
|
||||
int gpioSerialRead(unsigned user_gpio, void *buf, size_t bufSize) nogil
|
||||
int gpioSerialReadClose(unsigned user_gpio)
|
||||
|
||||
int gpioWaveCreate()
|
||||
int gpioWaveDelete(unsigned wave_id)
|
||||
int gpioWaveClear()
|
||||
|
||||
int gpioWaveTxSend(unsigned wave_id, unsigned wave_mode)
|
||||
int gpioWaveTxBusy()
|
||||
|
||||
int gpioWaveAddSerial(unsigned user_gpio, unsigned baud, unsigned data_bits, unsigned stop_bits, unsigned offset, unsigned numBytes, char *str)
|
||||
|
||||
int gpioCfgMemAlloc(unsigned memAllocMode)
|
||||
unsigned int gpioCfgGetInternals()
|
||||
int gpioCfgSetInternals(unsigned int cfgVal)
|
||||
|
||||
cdef int INPUT "PI_INPUT"
|
||||
cdef int OUTPUT "PI_OUTPUT"
|
||||
cdef int PI_DISABLE_FIFO_IF
|
||||
cdef int PI_DISABLE_SOCK_IF
|
||||
|
||||
cdef int PI_WAVE_MODE_ONE_SHOT
|
||||
|
||||
cdef unsigned PI_MEM_ALLOC_PAGEMAP
|
||||
|
||||
cdef extern from "unistd.h" nogil:
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
unsigned int usleep(unsigned int usecs)
|
||||
|
||||
def test():
|
||||
b = CythonRaspiBackend()
|
||||
b.open()
|
||||
while True:
|
||||
print(repr(b.read()))
|
||||
|
||||
cdef class CythonRaspiBackend(object):
|
||||
cdef int rx_pin
|
||||
cdef int tx_pin
|
||||
|
||||
def __init__(self, rx_pin=RX_PIN, tx_pin=TX_PIN):
|
||||
self.rx_pin = rx_pin
|
||||
self.tx_pin = tx_pin
|
||||
|
||||
cpdef open(self):
|
||||
# Enable startup debug
|
||||
gpioCfgSetInternals(gpioCfgGetInternals() | 8);
|
||||
|
||||
# Force usage of non-mailbox DMA
|
||||
gpioCfgMemAlloc(PI_MEM_ALLOC_PAGEMAP);
|
||||
|
||||
gpioCfgInterfaces(PI_DISABLE_FIFO_IF | PI_DISABLE_SOCK_IF);
|
||||
gpioInitialise()
|
||||
gpioWaveClear()
|
||||
gpioSetMode(self.tx_pin, INPUT)
|
||||
|
||||
# gpioSerClose...
|
||||
|
||||
cdef int resp = gpioSerialReadOpen(self.rx_pin, 9600, 9)
|
||||
if resp != 0:
|
||||
raise Exception('Serial open failed: %d' % resp)
|
||||
|
||||
cpdef read(self):
|
||||
cdef unsigned char buf[1024]
|
||||
cdef int read_size
|
||||
|
||||
with nogil:
|
||||
while 1:
|
||||
read_size = gpioSerialRead(self.rx_pin, &buf, sizeof(buf))
|
||||
if read_size > 0:
|
||||
break
|
||||
|
||||
usleep(100)
|
||||
|
||||
return bytes(buf[0:read_size])
|
||||
|
||||
cpdef write(self, data):
|
||||
cdef char* c_data = data
|
||||
gpioWaveAddSerial(self.tx_pin, 9600, 9, 6, 0, len(data), c_data)
|
||||
wid = gpioWaveCreate()
|
||||
|
||||
gpioSetMode(self.tx_pin, OUTPUT)
|
||||
gpioWaveTxSend(wid, PI_WAVE_MODE_ONE_SHOT)
|
||||
|
||||
while gpioWaveTxBusy():
|
||||
usleep(100)
|
||||
|
||||
gpioWaveDelete(wid)
|
||||
gpioSetMode(self.tx_pin, INPUT)
|
|
@ -0,0 +1,2 @@
|
|||
import cygpio
|
||||
cygpio.test()
|
|
@ -0,0 +1,7 @@
|
|||
from distutils.core import setup
|
||||
from distutils.extension import Extension
|
||||
from Cython.Build import cythonize
|
||||
|
||||
setup(
|
||||
ext_modules = cythonize([Extension("cygpio", ["cygpio.pyx"], libraries=["pigpio"])])
|
||||
)
|
|
@ -0,0 +1,133 @@
|
|||
with import <nixpkgs> {};
|
||||
|
||||
let
|
||||
upstream = with pkgs.python3Packages; {
|
||||
inherit buildPythonPackage;
|
||||
inherit fetchPypi;
|
||||
|
||||
inherit blinker;
|
||||
inherit cachetools;
|
||||
inherit cryptography;
|
||||
inherit cython;
|
||||
inherit flask;
|
||||
inherit flask_login;
|
||||
inherit flask_sqlalchemy;
|
||||
inherit flask_wtf;
|
||||
inherit mock;
|
||||
inherit prometheus_client;
|
||||
inherit pyjwt;
|
||||
inherit pytest;
|
||||
inherit qrcode;
|
||||
inherit raspberrypi-tools;
|
||||
inherit requests;
|
||||
inherit six;
|
||||
};
|
||||
|
||||
in with upstream; let
|
||||
websocket_client = buildPythonPackage rec {
|
||||
version = "0.40.0";
|
||||
pname = "websocket_client";
|
||||
|
||||
src = fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "1yz67wdjijrvwpx0a0f6wdfy8ajsvr9xbj5514ld452fqnh19b20";
|
||||
};
|
||||
|
||||
propagatedBuildInputs = [
|
||||
six
|
||||
];
|
||||
};
|
||||
|
||||
oauthlib = buildPythonPackage rec {
|
||||
pname = "oauthlib";
|
||||
version = "2.1.0";
|
||||
src = fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "0qj183fipjzw6ipiv2k10896y97sxvargnkb6db5qs61c5d6cddc";
|
||||
};
|
||||
|
||||
checkInputs = [ mock pytest ];
|
||||
propagatedBuildInputs = [ cryptography blinker pyjwt ];
|
||||
|
||||
checkPhase = ''
|
||||
py.test tests/
|
||||
'';
|
||||
};
|
||||
|
||||
requests_oauthlib = buildPythonPackage rec {
|
||||
pname = "requests-oauthlib";
|
||||
version = "1.0.0";
|
||||
src = fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "0gys581rqjdlv0whhqp5s2caxx66jzvb2hslxn8v7bypbbnbz1l8";
|
||||
};
|
||||
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [ oauthlib requests ];
|
||||
};
|
||||
|
||||
flask_oauthlib = buildPythonPackage rec {
|
||||
pname = "Flask-OAuthlib";
|
||||
version = "0.9.5";
|
||||
src = fetchPypi {
|
||||
inherit pname version;
|
||||
sha256 = "01llysn53jfrr9n02hvjcynrb28lh4rjqn18k2hhk6an09cq7znb";
|
||||
};
|
||||
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [ flask flask_sqlalchemy requests_oauthlib oauthlib ];
|
||||
};
|
||||
|
||||
spaceauth = buildPythonPackage rec {
|
||||
pname = "Flask-SpaceAuth";
|
||||
version = "0.2.0";
|
||||
|
||||
src = pkgs.fetchgit {
|
||||
url = "https://code.hackerspace.pl/informatic/flask-spaceauth";
|
||||
rev = "v${version}";
|
||||
sha256 = "000vg41lw4pyd10bvcqrp15y673qlpkllgppfhm48w7vk02r6zi2";
|
||||
};
|
||||
|
||||
propagatedBuildInputs = [ flask flask_login flask_oauthlib flask_wtf requests ];
|
||||
};
|
||||
|
||||
pigpio = stdenv.mkDerivation rec {
|
||||
pname = "pigpio";
|
||||
version = "74-q3k";
|
||||
buildFlags = [ "STRIPLIB=echo" "STRIP=echo" "CFLAGS=-g" ];
|
||||
installFlags = [ "DESTDIR=$(out)" "prefix=" ];
|
||||
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "q3k";
|
||||
repo = "pigpio";
|
||||
rev = "fa8c3ec41cb70da4d1868caec655d5f7d474573f";
|
||||
sha256 = "0shd2p1w8k0iz7v5j81w8hw6hy67zxd6r4mvz2xflabiwblr5zi3";
|
||||
};
|
||||
|
||||
dontStrip = true;
|
||||
propagatedBuildInputs = [ raspberrypi-tools ];
|
||||
};
|
||||
|
||||
cygpio = buildPythonPackage {
|
||||
pname = "cygpio";
|
||||
version = "1.0.0";
|
||||
src = ./cygpio;
|
||||
propagatedBuildInputs = [ pigpio cython ];
|
||||
};
|
||||
|
||||
in buildPythonPackage rec {
|
||||
name = "bitvend";
|
||||
src = ./.;
|
||||
doCheck = false;
|
||||
propagatedBuildInputs = [
|
||||
cygpio
|
||||
flask
|
||||
flask_sqlalchemy
|
||||
websocket_client
|
||||
cachetools
|
||||
requests
|
||||
prometheus_client
|
||||
spaceauth
|
||||
qrcode
|
||||
];
|
||||
}
|
|
@ -7,7 +7,7 @@ Type=simple
|
|||
User=bitvend
|
||||
Environment=BITVEND_SETTINGS=bitvend.cfg
|
||||
WorkingDirectory=/var/bitvend
|
||||
ExecStart=/usr/bin/python3 -u /var/bitvend/bitvend.py
|
||||
ExecStart=/usr/bin/python3 -u /var/bitvend/bitvend-run.py
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
- hosts: bitvend
|
||||
tasks:
|
||||
- hostname: name={{ inventory_hostname }}
|
||||
|
||||
- apt: name=dphys-swapfile state=absent
|
||||
- file: name=/var/swap state=absent
|
||||
- mount: name=/var/log src=tmpfs fstype=tmpfs state=present opts="defaults,noatime,nosuid,mode=0755,size=50m"
|
||||
|
||||
- apt: name="{{ item }}" state=present
|
||||
with_items:
|
||||
- pigpio
|
||||
|
|
|
@ -7,6 +7,12 @@ try:
|
|||
except ImportError:
|
||||
import Queue as queue
|
||||
|
||||
try:
|
||||
import cygpio
|
||||
except ImportError:
|
||||
raise
|
||||
cygpio = None
|
||||
|
||||
from mdb.utils import compute_checksum, compute_chk, bcd_decode
|
||||
from mdb.constants import *
|
||||
from mdb.backend import RaspiBackend, DummyBackend, SerialBackend, pigpio
|
||||
|
@ -18,6 +24,10 @@ class MDBRequest(object):
|
|||
processed = False
|
||||
|
||||
def __init__(self, command):
|
||||
self.reset(command)
|
||||
|
||||
def reset(self, command):
|
||||
self.processed = False
|
||||
self.timestamp = time.time()
|
||||
self.command = command
|
||||
self.data = bytearray()
|
||||
|
@ -41,7 +51,7 @@ class MDBRequest(object):
|
|||
return False
|
||||
@property
|
||||
def ack(self):
|
||||
return self.data[-1] == 0x00
|
||||
return len(self.data) and self.data[-1] == 0x00
|
||||
|
||||
def __repr__(self):
|
||||
return '<MDBRequest 0x%02x [%s] chk:%r>' % (
|
||||
|
@ -60,20 +70,26 @@ class MDBDevice(object):
|
|||
def __init__(self, app=None):
|
||||
self.logger = logging.getLogger(type(self).__name__)
|
||||
self.poll_queue = queue.Queue()
|
||||
if pigpio:
|
||||
if cygpio:
|
||||
self.backend = cygpio.CythonRaspiBackend()
|
||||
self.logger.warning('Running with FAST CYTHON BACKEND')
|
||||
elif pigpio:
|
||||
self.backend = RaspiBackend()
|
||||
else:
|
||||
self.logger.warning('Running with dummy backend device')
|
||||
self.backend = SerialBackend()
|
||||
|
||||
def initialize(self):
|
||||
self.logger.info('Initializing...')
|
||||
self.logger.info('Initializing... %r backend', self.backend)
|
||||
self.backend.open()
|
||||
# here should IO / connection initizliation go
|
||||
|
||||
def run(self):
|
||||
self.initialize()
|
||||
|
||||
self.current_request = MDBRequest(0)
|
||||
self.current_request.processed = True
|
||||
|
||||
while True:
|
||||
data = self.backend.read()
|
||||
for b in range(0, len(data), 2):
|
||||
|
@ -85,7 +101,7 @@ class MDBDevice(object):
|
|||
self.logger.info('Got response: %d',self.current_request.data[-1])
|
||||
self.poll_msg = []
|
||||
|
||||
self.current_request = MDBRequest(data[b])
|
||||
self.current_request.reset(data[b])
|
||||
self.send_buffer = None
|
||||
elif self.current_request:
|
||||
if self.current_request.processed and data[b] == 0xaa and self.send_buffer:
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf mkOption types;
|
||||
|
||||
cfg = config.services.bitvend;
|
||||
|
||||
bitvend = (import ./default.nix);
|
||||
cfgFile = pkgs.writeText "bitvend.cfg"
|
||||
''
|
||||
SQLALCHEMY_DATABASE_URI = 'sqlite:///${cfg.stateDir}/bitvend.db'
|
||||
SPACEAUTH_CONSUMER_KEY = '${cfg.spaceauthConsumerKey}'
|
||||
SPACEAUTH_CONSUMER_SECRET = '${cfg.spaceauthConsumerSecret}'
|
||||
BLOCKCYPHER_TOKEN = '${cfg.blockcypherToken}'
|
||||
SECRET_KEY = '${cfg.secretKey}'
|
||||
'';
|
||||
|
||||
|
||||
in {
|
||||
options.services.bitvend = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable bitvend";
|
||||
};
|
||||
stateDir = mkOption {
|
||||
type = types.path;
|
||||
default = "/var/db/bitvend";
|
||||
description = "Location of bitvend's config/data directory";
|
||||
};
|
||||
spaceauthConsumerKey = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "spaceauth consumer key";
|
||||
};
|
||||
spaceauthConsumerSecret = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "spaceauth consumer secret";
|
||||
};
|
||||
blockcypherToken = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "blockcypher token";
|
||||
};
|
||||
secretKey = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "blockcypher token";
|
||||
};
|
||||
hostName = mkOption {
|
||||
type = types.str;
|
||||
default = "vending.waw.hackerspace.pl";
|
||||
description = "hostname";
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.bitvend = {
|
||||
environment = {
|
||||
BITVEND_SETTINGS = cfgFile;
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
script = ''
|
||||
${bitvend}/bin/bitvend-run.py
|
||||
'';
|
||||
};
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${cfg.stateDir}' 0750 'root' 'root' - -"
|
||||
];
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
appendHttpConfig = ''
|
||||
proxy_cache_path /tmp/nginx-cache levels=1:2 keys_zone=qrcode_cache:10m max_size=50m inactive=60m;
|
||||
'';
|
||||
virtualHosts."${cfg.hostName}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:5000";
|
||||
};
|
||||
locations."/qrcode/" = {
|
||||
proxyPass = "http://127.0.0.1:5000";
|
||||
extraConfig = ''
|
||||
add_header X-Proxy-Cache $upstream_cache_status;
|
||||
proxy_cache qrcode_cache;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue