From 37ba4aa07b62fc11c2ee28781e7827bb49f04c6f Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Sun, 10 Jun 2018 19:48:31 +0200 Subject: [PATCH 1/8] deployment: get rid of swapfile --- deployment/playbook.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deployment/playbook.yml b/deployment/playbook.yml index 70a9cfe..c0b2212 100644 --- a/deployment/playbook.yml +++ b/deployment/playbook.yml @@ -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 From 9adff5141e462414589c954f45e19383e52bcbe5 Mon Sep 17 00:00:00 2001 From: Piotr Dobrowolski Date: Sun, 10 Jun 2018 19:49:49 +0200 Subject: [PATCH 2/8] cygpio: basic cython-based MDB backend for raspi & pigpio --- cygpio/cygpio.pyx | 86 +++++++++++++++++++++++++++++++++++++++++++ cygpio/cygpio_test.py | 2 + cygpio/setup.py | 7 ++++ 3 files changed, 95 insertions(+) create mode 100644 cygpio/cygpio.pyx create mode 100644 cygpio/cygpio_test.py create mode 100644 cygpio/setup.py diff --git a/cygpio/cygpio.pyx b/cygpio/cygpio.pyx new file mode 100644 index 0000000..9049cda --- /dev/null +++ b/cygpio/cygpio.pyx @@ -0,0 +1,86 @@ +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) + + 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 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): + 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) diff --git a/cygpio/cygpio_test.py b/cygpio/cygpio_test.py new file mode 100644 index 0000000..a9d8108 --- /dev/null +++ b/cygpio/cygpio_test.py @@ -0,0 +1,2 @@ +import cygpio +cygpio.test() diff --git a/cygpio/setup.py b/cygpio/setup.py new file mode 100644 index 0000000..4ce5599 --- /dev/null +++ b/cygpio/setup.py @@ -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"])]) + ) From 445913037077a7eeb66aeb6c06b731655b6b4c59 Mon Sep 17 00:00:00 2001 From: voltar13 Date: Wed, 30 Jan 2019 21:02:44 +0100 Subject: [PATCH 3/8] Fix bitcoin payments by adding blockcypher token --- bitvend/processor.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/bitvend/processor.py b/bitvend/processor.py index 37732f0..2dc4ce0 100644 --- a/bitvend/processor.py +++ b/bitvend/processor.py @@ -15,12 +15,15 @@ class PaymentProcessor(threading.Thread): last_pong = 0 app = None - def __init__(self, device, input_address=None, chain_id=None, app=None): + def __init__( + self, device, input_address=None, chain_id=None, app=None, + token=None): super(PaymentProcessor, self).__init__() self.device = device self.input_address = input_address self.chain_id = chain_id self.logger = logging.getLogger(type(self).__name__) + self.token = token if app: self.init_app(app) @@ -31,6 +34,7 @@ class PaymentProcessor(threading.Thread): if not self.input_address: self.input_address = self.app.config['INPUT_ADDRESS'] self.chain_id = self.app.config['BLOCKCYPHER_CHAIN'] + self.token = self.app.config['BLOCKCYPHER_TOKEN'] def run(self): self.logger.info('Starting...') @@ -38,12 +42,13 @@ class PaymentProcessor(threading.Thread): while True: try: ws = websocket.WebSocketApp( - "wss://socket.blockcypher.com/v1/%s" % self.chain_id, + "wss://socket.blockcypher.com/v1/%s?token=%s" \ + % (self.chain_id, self.token), on_message=self.on_message, on_error=self.on_error, - on_close=self.on_close) + on_close=self.on_close, + on_open=self.on_open) - ws.on_open = self.on_open ws.run_forever(ping_timeout=20, ping_interval=30) except: self.logger.exception('run_forever failed') From 9ea05b5c701ad662d4f5cc2ca27632e7e2ee3140 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sun, 23 Feb 2020 10:57:44 +0100 Subject: [PATCH 4/8] hack: pull changes from old rpi --- bitvend/admin.py | 19 +++++++++++++++++++ bitvend/default_settings.py | 2 +- bitvend/forms.py | 1 - bitvend/templates/base.html | 4 ++-- bitvend/templates/index.html | 12 ++++++------ bitvend/utils.py | 19 +++++++++++++++---- bitvend/views.py | 2 ++ mdb/device.py | 33 ++++++++++++++++++++++++--------- 8 files changed, 69 insertions(+), 23 deletions(-) diff --git a/bitvend/admin.py b/bitvend/admin.py index c803181..e36412e 100644 --- a/bitvend/admin.py +++ b/bitvend/admin.py @@ -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('/') diff --git a/bitvend/default_settings.py b/bitvend/default_settings.py index 5536877..89ad248 100644 --- a/bitvend/default_settings.py +++ b/bitvend/default_settings.py @@ -40,4 +40,4 @@ ITEMS = [ }, ] -DEBT_LIMIT = 2500 +DEBT_LIMIT = 1500 diff --git a/bitvend/forms.py b/bitvend/forms.py index 203b3d5..84805e1 100644 --- a/bitvend/forms.py +++ b/bitvend/forms.py @@ -45,5 +45,4 @@ class TransferForm(FlaskForm): class ManualForm(FlaskForm): amount = DecimalUnityField("Amount", default=0, validators=[ - NumberRange(min=1), ]) diff --git a/bitvend/templates/base.html b/bitvend/templates/base.html index 3a8b49b..4194b94 100644 --- a/bitvend/templates/base.html +++ b/bitvend/templates/base.html @@ -77,10 +77,10 @@ {% endif %} diff --git a/bitvend/templates/index.html b/bitvend/templates/index.html index 1960b67..5f63e7e 100644 --- a/bitvend/templates/index.html +++ b/bitvend/templates/index.html @@ -53,8 +53,8 @@ NameBalance - {% for user in hallofshame %} - {{ user }}{{ format_currency(user.balance) }} + {% for user, balance in hallofshame %} + {{ user }}{{ format_currency(balance) }} {% else %} Wow! Nobody's due! {% endfor %} @@ -65,8 +65,8 @@ NameAmountPurchases - {% for user in hallofaddicts %} - {{ user }}{{ format_currency(user.purchase_amount) }}{{ user.purchase_count }} + {% for user, purchase_amount, purchase_count in hallofaddicts %} + {{ user }}{{ format_currency(purchase_amount) }}{{ purchase_count }} {% else %} Huh? {% endfor %} @@ -132,7 +132,7 @@
{{ format_currency(item.value) }} - {{ format_btc(from_local_currency(item.value*1.03)) }} + {{ format_btc(from_local_currency(item.value*1.03, True)) }}

{{ item.name }}

@@ -140,7 +140,7 @@
- {% 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))) %} {{ config['INPUT_ADDRESS'] }} diff --git a/bitvend/utils.py b/bitvend/utils.py index d360477..e761f4a 100644 --- a/bitvend/utils.py +++ b/bitvend/utils.py @@ -6,14 +6,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) - rate = get_exchange_rate() + 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 - rate = get_exchange_rate() + try: + rate = get_exchange_rate() + except: + if safe: + return 0 + raise + return int(val / rate * 1000000) def sat_to_btc(amount): diff --git a/bitvend/views.py b/bitvend/views.py index 7e424cb..23e8147 100644 --- a/bitvend/views.py +++ b/bitvend/views.py @@ -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) \ diff --git a/mdb/device.py b/mdb/device.py index 20ea546..9ea0e6e 100644 --- a/mdb/device.py +++ b/mdb/device.py @@ -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, 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 '' % ( @@ -60,31 +70,36 @@ 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 = DummyBackend() 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): if data[b+1]: - if self.current_request: # and not self.current_request.processed: - self.logger.debug(self.current_request) - if self.current_request.processed and self.current_request.ack: - self.logger.info('Got response: %d',self.current_request.data[-1]) - self.poll_msg = [] + self.logger.debug(self.current_request) + if self.current_request.processed and self.current_request.ack: + 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: From 75c222852b498c87ed3230d6a496549634b1c31c Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Tue, 11 Feb 2020 22:21:29 +0100 Subject: [PATCH 5/8] default.nix: implement This paves the way to hosting bitvend with NixOS. Getting this to work required pulling in flask-oauthlib and a bunch of older dependencies. This isn't great, but before we migrate flask-spaceauth to use authlib that's what we have to do. We also build pigpio/cygpio. pigpio should get upstreamed into nixpkgs. We also rename bitvend.py to bitvend-run.py to unconfuse python paths. To test: nix build result/bin/bitvend-run.py --- .gitignore | 1 + MANIFEST.in | 3 + bitvend.py => bitvend-run.py | 2 + bitvend/utils.py | 2 + default.nix | 128 +++++++++++++++++++++++++++++++++++ deployment/bitvend.service | 2 +- setup.py | 9 +++ 7 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 MANIFEST.in rename bitvend.py => bitvend-run.py (94%) create mode 100644 default.nix create mode 100644 setup.py diff --git a/.gitignore b/.gitignore index 85ea788..c5ec480 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.cfg *.db *.sqlite3 +result diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..0b89ab0 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +graft bitvend/static +graft bitvend/templates +global-exclude *.pyc diff --git a/bitvend.py b/bitvend-run.py similarity index 94% rename from bitvend.py rename to bitvend-run.py index 589ad98..0cbd89a 100644 --- a/bitvend.py +++ b/bitvend-run.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + import logging logging.basicConfig(level=logging.INFO) # noqa diff --git a/bitvend/utils.py b/bitvend/utils.py index e761f4a..24914cf 100644 --- a/bitvend/utils.py +++ b/bitvend/utils.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + import cachetools import requests diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..3afa202 --- /dev/null +++ b/default.nix @@ -0,0 +1,128 @@ +with import {}; + +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 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"; + installFlags = [ "DESTDIR=$(out)" "prefix=" ]; + + src = pkgs.fetchFromGitHub { + owner = "joan2937"; + repo = "pigpio"; + rev = "v${version}"; + sha256 = "1arq051dbki50rwhzdxjba3ispnl4vdw7mr244f5hmrk0p34frcy"; + }; + }; + + 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 + ]; +} diff --git a/deployment/bitvend.service b/deployment/bitvend.service index 1bac993..826515b 100644 --- a/deployment/bitvend.service +++ b/deployment/bitvend.service @@ -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] diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..eb8c91b --- /dev/null +++ b/setup.py @@ -0,0 +1,9 @@ +from setuptools import setup, find_packages + +setup( + name="bitvend", + version="1.0", + packages=find_packages(), + include_package_data=True, + scripts=['bitvend-run.py'], +) From 25b41d64960765a33cf2b409f3b3c9247df164fa Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Wed, 12 Feb 2020 16:38:28 +0100 Subject: [PATCH 6/8] module.nix: init This isn't great, but hey, it works. --- bitvend/__init__.py | 1 + module.nix | 110 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 module.nix diff --git a/bitvend/__init__.py b/bitvend/__init__.py index 0513078..2ab00a6 100644 --- a/bitvend/__init__.py +++ b/bitvend/__init__.py @@ -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 diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..b8149f5 --- /dev/null +++ b/module.nix @@ -0,0 +1,110 @@ +{ config, lib, pkgs, ... }: + +let + inherit (lib) mkIf mkOption types; + + cfg = config.services.bitvend; + + bitvendUser = "bitvend"; + bitvendGroup = "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 { + ids.uids.bitvend = 2137; + ids.gids.bitvend = 2137; + + users.users.bitvend = { + name = bitvendUser; + group = bitvendGroup; + uid = config.ids.uids.bitvend; + description = "Bitvend daemon user"; + home = cfg.stateDir; + }; + users.groups.bitvend = { + name = bitvendGroup; + gid = config.ids.gids.bitvend; + }; + systemd.services.bitvend = { + environment = { + BITVEND_SETTINGS = cfgFile; + }; + wantedBy = [ "multi-user.target" ]; + script = '' + ${bitvend}/bin/bitvend-run.py + ''; + serviceConfig = { + User = bitvendUser; + }; + }; + systemd.tmpfiles.rules = [ + "d '${cfg.stateDir}' 0750 '${bitvendUser}' '${bitvendGroup}' - -" + ]; + 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; + ''; + }; + }; + }; + }; +} From 1735eb0cf6f0cf20580555a5989ef4efd786fd2b Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sun, 23 Feb 2020 15:13:16 +0100 Subject: [PATCH 7/8] *: fixes for 64-bit RPi3 via NixOS We force pigpio to not use the old broadcom fork mailbox interface, and we use a fork of pigpio that work with u-boot. --- cygpio/cygpio.pyx | 12 ++++++++++++ default.nix | 11 +++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/cygpio/cygpio.pyx b/cygpio/cygpio.pyx index 9049cda..dd0a931 100644 --- a/cygpio/cygpio.pyx +++ b/cygpio/cygpio.pyx @@ -20,6 +20,10 @@ cdef extern from "pigpio.h": 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 @@ -27,6 +31,8 @@ cdef extern from "pigpio.h": 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) @@ -46,6 +52,12 @@ cdef class CythonRaspiBackend(object): self.tx_pin = tx_pin cpdef open(self): + # Enable full on 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() diff --git a/default.nix b/default.nix index 3afa202..b83484f 100644 --- a/default.nix +++ b/default.nix @@ -18,6 +18,7 @@ let inherit pyjwt; inherit pytest; inherit qrcode; + inherit raspberrypi-tools; inherit requests; inherit six; }; @@ -92,15 +93,17 @@ in with upstream; let pigpio = stdenv.mkDerivation rec { pname = "pigpio"; - version = "74"; + version = "74-q3k"; installFlags = [ "DESTDIR=$(out)" "prefix=" ]; src = pkgs.fetchFromGitHub { - owner = "joan2937"; + owner = "q3k"; repo = "pigpio"; - rev = "v${version}"; - sha256 = "1arq051dbki50rwhzdxjba3ispnl4vdw7mr244f5hmrk0p34frcy"; + rev = "5a0b27c997631b3ba1a7778a176b6f5462233be4"; + sha256 = "1b55bzfsyghd2lrfqmz6g935zsmwnhbcscb4g11hxm3g7a68g9vv"; }; + + propagatedBuildInputs = [ raspberrypi-tools ]; }; cygpio = buildPythonPackage { From 621016bd9c16d64b4d51a6cb7a87e390d510508f Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Sun, 23 Feb 2020 16:12:11 +0100 Subject: [PATCH 8/8] module.nix: run as root --- cygpio/cygpio.pyx | 2 +- default.nix | 6 ++++-- module.nix | 22 +--------------------- 3 files changed, 6 insertions(+), 24 deletions(-) diff --git a/cygpio/cygpio.pyx b/cygpio/cygpio.pyx index dd0a931..4c689e3 100644 --- a/cygpio/cygpio.pyx +++ b/cygpio/cygpio.pyx @@ -52,7 +52,7 @@ cdef class CythonRaspiBackend(object): self.tx_pin = tx_pin cpdef open(self): - # Enable full on debug + # Enable startup debug gpioCfgSetInternals(gpioCfgGetInternals() | 8); # Force usage of non-mailbox DMA diff --git a/default.nix b/default.nix index b83484f..de8951b 100644 --- a/default.nix +++ b/default.nix @@ -94,15 +94,17 @@ in with upstream; let 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 = "5a0b27c997631b3ba1a7778a176b6f5462233be4"; - sha256 = "1b55bzfsyghd2lrfqmz6g935zsmwnhbcscb4g11hxm3g7a68g9vv"; + rev = "fa8c3ec41cb70da4d1868caec655d5f7d474573f"; + sha256 = "0shd2p1w8k0iz7v5j81w8hw6hy67zxd6r4mvz2xflabiwblr5zi3"; }; + dontStrip = true; propagatedBuildInputs = [ raspberrypi-tools ]; }; diff --git a/module.nix b/module.nix index b8149f5..bdfd06e 100644 --- a/module.nix +++ b/module.nix @@ -5,9 +5,6 @@ let cfg = config.services.bitvend; - bitvendUser = "bitvend"; - bitvendGroup = "bitvend"; - bitvend = (import ./default.nix); cfgFile = pkgs.writeText "bitvend.cfg" '' @@ -58,20 +55,6 @@ in { }; }; config = mkIf cfg.enable { - ids.uids.bitvend = 2137; - ids.gids.bitvend = 2137; - - users.users.bitvend = { - name = bitvendUser; - group = bitvendGroup; - uid = config.ids.uids.bitvend; - description = "Bitvend daemon user"; - home = cfg.stateDir; - }; - users.groups.bitvend = { - name = bitvendGroup; - gid = config.ids.gids.bitvend; - }; systemd.services.bitvend = { environment = { BITVEND_SETTINGS = cfgFile; @@ -80,12 +63,9 @@ in { script = '' ${bitvend}/bin/bitvend-run.py ''; - serviceConfig = { - User = bitvendUser; - }; }; systemd.tmpfiles.rules = [ - "d '${cfg.stateDir}' 0750 '${bitvendUser}' '${bitvendGroup}' - -" + "d '${cfg.stateDir}' 0750 'root' 'root' - -" ]; networking.firewall.allowedTCPPorts = [ 80 443 ]; services.nginx = {