diff --git a/build.bat b/build.bat new file mode 100644 index 0000000..cc1b78e --- /dev/null +++ b/build.bat @@ -0,0 +1,3 @@ +@echo off +pip install nuitka -q +python -m nuitka --standalone --windows-console-mode=force --windows-icon-from-ico=main.ico main.py diff --git a/main.ico b/main.ico new file mode 100644 index 0000000..68863ea Binary files /dev/null and b/main.ico differ diff --git a/main.py b/main.py index 9251974..9bbe401 100644 --- a/main.py +++ b/main.py @@ -1,10 +1,109 @@ -import hashlib import io -import json import os +import sys +import json +import hashlib +import tempfile + from flask import Flask, request, send_from_directory +def _fd(f): + return f.fileno() if hasattr(f, 'fileno') else f + + +if os.name == 'nt': + import msvcrt + from ctypes import (sizeof, c_ulong, c_void_p, c_int64, Structure, Union, POINTER, windll, byref) + from ctypes.wintypes import BOOL, DWORD, HANDLE + + LOCK_SH = 0x0 + LOCK_NB = 0x1 + LOCK_EX = 0x2 + LOCK_UN = 0x9 + + if sizeof(c_ulong) != sizeof(c_void_p): + ULONG_PTR = c_int64 + else: + ULONG_PTR = c_ulong + + PVOID = c_void_p + + + class _OFFSET(Structure): + _fields_ = [ + ('Offset', DWORD), + ('OffsetHigh', DWORD) + ] + + + class _OFFSET_UNION(Union): + _fields_ = [ + ('_offset', _OFFSET), + ('Pointer', PVOID) + ] + _anonymous_ = ['_offset'] + + + class OVERLAPPED(Structure): + _fields_ = [ + ('Internal', ULONG_PTR), + ('InternalHigh', ULONG_PTR), + ('_offset_union', _OFFSET_UNION), + ('hEvent', HANDLE) + ] + _anonymous_ = ['_offset_union'] + + + LPOVERLAPPED = POINTER(OVERLAPPED) + LockFileEx = windll.kernel32.LockFileEx + LockFileEx.restype = BOOL + LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED] + UnlockFileEx = windll.kernel32.UnlockFileEx + UnlockFileEx.restype = BOOL + UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED] + + + def flock(f, flags): + hfile = msvcrt.get_osfhandle(_fd(f)) + overlapped = OVERLAPPED() + if flags == LOCK_UN: + ret = UnlockFileEx( + hfile, + 0, + 0, + 0xFFFF0000, + byref(overlapped) + ) + else: + ret = LockFileEx( + hfile, + flags, + 0, + 0, + 0xFFFF0000, + byref(overlapped) + ) + return bool(ret) +else: + try: + import fcntl + + LOCK_SH = fcntl.LOCK_SH + LOCK_NB = fcntl.LOCK_NB + LOCK_EX = fcntl.LOCK_EX + LOCK_UN = fcntl.LOCK_UN + except (ImportError, AttributeError): + LOCK_EX = LOCK_SH = LOCK_NB = 0 + + + def flock(f, flags): + return flags == LOCK_UN + else: + def flock(f, flags): + return fcntl.flock(_fd(f), flags) == 0 + + def getJson(file, data=None): if os.path.exists(file): try: @@ -28,22 +127,8 @@ def md5(input_data): return md5_object.hexdigest() -print('Scanning apps...') www_home = os.path.abspath(os.path.join(os.path.dirname(__file__), 'apps')) app_data = [] -for item in os.listdir(www_home): - if (item.endswith('.zip')) is bool(1): - packages = os.path.join(www_home, item) - manifest = os.path.join(www_home, '%s.%s' % (os.path.splitext(os.path.basename(item))[0], 'MANIFEST')) - if (os.path.isfile(packages) and os.path.isfile(manifest)) is bool(1): - info = getJson(manifest, {}) - try: - if (isinstance(info['appName'], str) and isinstance(info['HomeFolderName'], str) and isinstance(info['shortcutMapping'], list)) is bool(0): - continue - app_data.append({'packages_path': item, 'md5': md5(open(packages, 'rb')), 'manifest': info}) - except KeyError: - pass - app = Flask(__name__) @@ -66,4 +151,23 @@ def www(filename): if __name__ == '__main__': - app.run(port=9988) + f_lock = open(file=os.path.abspath(os.path.join(tempfile.gettempdir(), '%s.lock' % hashlib.md5(bytes(__file__, encoding='utf-8')).hexdigest()[:16])), mode='w', encoding='utf-8') + if (not flock(f_lock, LOCK_EX | LOCK_NB)) == 1: + sys.exit(1) + else: + print('Scanning apps...') + if os.path.exists(www_home): + for item in os.listdir(www_home): + if (item.endswith('.zip')) is bool(1): + packages = os.path.join(www_home, item) + manifest = os.path.join(www_home, '%s.%s' % (os.path.splitext(os.path.basename(item))[0], 'MANIFEST')) + if (os.path.isfile(packages) and os.path.isfile(manifest)) is bool(1): + info = getJson(manifest, {}) + try: + if (isinstance(info['appName'], str) and isinstance(info['HomeFolderName'], str) and isinstance(info['shortcutMapping'], list)) is bool(0): + continue + app_data.append({'packages_path': item, 'md5': md5(open(packages, 'rb')), 'manifest': info}) + except KeyError: + pass + print('Starting web server...') + app.run(host='0.0.0.0', port=9988)