Browse Source

make qr size deterministic and move hash performance tests into test dir

Daniel Sheffield 1 year ago
parent
commit
8604ff3207
5 changed files with 44 additions and 45 deletions
  1. 0 32
      app/rest/hash_util.py
  2. 3 3
      app/rest/pyapi.py
  3. 21 7
      app/rest/qr.py
  4. 6 2
      app/rest/save.py
  5. 14 1
      test/rest/test_hash_util.py

File diff suppressed because it is too large
+ 0 - 32
app/rest/hash_util.py


+ 3 - 3
app/rest/pyapi.py

@@ -112,7 +112,7 @@ def clip():
         else:
         else:
             content = None
             content = None
         link = f'{LOCATION}/clip/{_hash}' if content else f'{LOCATION}/clip'
         link = f'{LOCATION}/clip/{_hash}' if content else f'{LOCATION}/clip'
-        svg = get_qr_code(link if not content or len(content) > 300 else content)
+        svg = get_qr_code(content, fallback=link)
 
 
         response.content_type = 'text/html; charset=utf-8'
         response.content_type = 'text/html; charset=utf-8'
         form = template(
         form = template(
@@ -146,7 +146,7 @@ def clip():
             disabled=False
             disabled=False
         )
         )
         link = f'{LOCATION}/clip'
         link = f'{LOCATION}/clip'
-        svg = get_qr_code(link if not content or len(content) > 300 else content)
+        svg = get_qr_code(content, fallback=link)
         return template(
         return template(
             'paste',
             'paste',
             form=form,
             form=form,
@@ -221,7 +221,7 @@ def goto():
             return redirect(target)
             return redirect(target)
 
 
         link = f'{LOCATION}/goto/{_hash}' if content else f'{LOCATION}/goto'
         link = f'{LOCATION}/goto/{_hash}' if content else f'{LOCATION}/goto'
-        svg = get_qr_code(link if not content or len(content) > 300 else content)
+        svg = get_qr_code(content, fallback=link)
         disabled = True if content else False
         disabled = True if content else False
         response.content_type = 'text/html; charset=utf-8'
         response.content_type = 'text/html; charset=utf-8'
         form = template(
         form = template(

+ 21 - 7
app/rest/qr.py

@@ -1,20 +1,34 @@
 import io
 import io
+from typing import Union
 from qrcode import QRCode
 from qrcode import QRCode
-from qrcode.constants import ERROR_CORRECT_H
+from qrcode.constants import ERROR_CORRECT_L, ERROR_CORRECT_M, ERROR_CORRECT_Q, ERROR_CORRECT_H
 from qrcode.image.styledpil import StyledPilImage
 from qrcode.image.styledpil import StyledPilImage
 from qrcode.image.svg import SvgPathImage
 from qrcode.image.svg import SvgPathImage
 from qrcode.image.styles.moduledrawers.svg import SvgCircleDrawer
 from qrcode.image.styles.moduledrawers.svg import SvgCircleDrawer
 from qrcode.image.styles.colormasks import RadialGradiantColorMask
 from qrcode.image.styles.colormasks import RadialGradiantColorMask
 
 
-def get_qr_code(data: bytes):
-    qr = QRCode(error_correction=ERROR_CORRECT_H)
-    qr.add_data(data.encode('utf-8'))
+QR_MAX_BYTES = {
+    ERROR_CORRECT_H: 1273,
+    ERROR_CORRECT_Q: 1663,
+    ERROR_CORRECT_M: 2331,
+    ERROR_CORRECT_L: 2953,
+}
+def get_qr_code(data: Union[bytes, str], fallback: Union[bytes, str] = None):
+    err_lvl = ERROR_CORRECT_H
+    qr = QRCode(error_correction=err_lvl)
+    if data is not None and isinstance(data, str):
+        data = data.encode('utf-8')
+    if fallback is not None and isinstance(fallback, str):
+        fallback = fallback.encode('utf-8')
+    if fallback is not None and data and len(data) > QR_MAX_BYTES[err_lvl]:
+        qr.add_data(fallback, optimize=0)
+    else:
+        qr.add_data(data or fallback, optimize=0)
 
 
-    img_1 = qr.make_image(image_factory=SvgPathImage,)
-    #module_drawer=SvgCircleDrawer())
+    img_1 = qr.make_image(image_factory=SvgPathImage)
     with io.BytesIO() as f:
     with io.BytesIO() as f:
         img_1.save(f)
         img_1.save(f)
         f.flush()
         f.flush()
         ret = f.getvalue()
         ret = f.getvalue()
     return ret
     return ret
-    
+    

+ 6 - 2
app/rest/save.py

@@ -5,7 +5,7 @@
 # THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
 # THIS SOFTWARE IS PROVIDED AS IS WITHOUT WARRANTY
 
 
 from hashlib import blake2b
 from hashlib import blake2b
-from io import BufferedRandom
+from io import BufferedRandom, BytesIO
 import os
 import os
 from uuid import uuid4
 from uuid import uuid4
 from .hash_util import DIGEST_SIZE_BYTES, blake, bytes_to_base32
 from .hash_util import DIGEST_SIZE_BYTES, blake, bytes_to_base32
@@ -34,7 +34,11 @@ def save_upload(name: str, content: BufferedRandom, root='app/rest/static') -> s
     unique = uuid4()
     unique = uuid4()
     fd = os.open(f'{tmpdir}/{unique.hex}', os.O_WRONLY | os.O_TRUNC | os.O_CREAT, 0o600)
     fd = os.open(f'{tmpdir}/{unique.hex}', os.O_WRONLY | os.O_TRUNC | os.O_CREAT, 0o600)
     with open(fd, "wb") as f:
     with open(fd, "wb") as f:
-        while content.peek(1):
+        done = False
+        if isinstance(content, BytesIO):
+            f.write(content.getvalue())
+            done = True
+        while not done and content.peek(1):
             seg = content.read(1024)
             seg = content.read(1024)
             f.write(seg)
             f.write(seg)
     
     

File diff suppressed because it is too large
+ 14 - 1
test/rest/test_hash_util.py


Some files were not shown because too many files changed in this diff