def wait_for_abortRequested(proc, monitor): monitor.closing.wait() log.info("torrserverd: exiting torrserverd daemon") try: if proc is not None: proc.terminate() except OSError: pass # Process already exited, nothing to terminate log.info("torrserverd: torrserverd daemon exited")
def system_information(): build = xbmc.getInfoLabel("System.BuildVersion") log.info("System information: %(os)s_%(arch)s %(version)s" % PLATFORM) log.info("Kodi build version: %s" % build) log.info("OS type: %s" % platform.system()) log.info("uname: %s" % repr(platform.uname())) return PLATFORM
def dump_version(): try: p = platform.platform() except: p = "Could not detect" log.info("""Python version: %s dist: %s linux_distribution: %s system: %s machine: %s platform: %s uname: %s version: %s mac_ver: %s """ % (sys.version.split('\n'), str(platform.dist()), linux_distribution(), platform.system(), platform.machine(), p, platform.uname(), platform.version(), platform.mac_ver()))
def start_torrserverd(**kwargs): torrserver_dir, torrserver_binary = get_torrserver_binary() log.info("Binary dir: %s, item: %s " % (torrserver_dir, torrserver_binary)) if torrserver_dir is False or torrserver_binary is False: return False SW_HIDE = 0 STARTF_USESHOWWINDOW = 1 ADDON_PORT = ADDON.getSetting("torrserver_port") database_path = getShortPath( os.path.join( xbmc.translatePath(ADDON.getAddonInfo("profile")).decode('utf-8'))) args = [torrserver_binary, "-p", ADDON_PORT, "-d", database_path] kwargs["cwd"] = torrserver_dir if PLATFORM["os"] == "windows": args[0] = getShortPath(torrserver_binary) kwargs["cwd"] = getShortPath(torrserver_dir) si = subprocess.STARTUPINFO() si.dwFlags = STARTF_USESHOWWINDOW si.wShowWindow = SW_HIDE clear_fd_inherit_flags() kwargs["startupinfo"] = si else: env = os.environ.copy() env["LD_LIBRARY_PATH"] = "%s:%s" % (torrserver_dir, env.get("LD_LIBRARY_PATH", "")) kwargs["env"] = env kwargs["close_fds"] = True wait_counter = 1 log.debug("Checking for visible") while xbmc.getCondVisibility( 'Window.IsVisible(10140)') or xbmc.getCondVisibility( 'Window.IsActive(10140)'): if wait_counter == 1: log.info( 'Add-on settings currently opened, waiting before starting...') if wait_counter > 300: break time.sleep(1) wait_counter += 1 log.info("torrserverd: start args: %s, kw: %s" % (args, kwargs)) if hasSubprocess: return subprocess.Popen(args, **kwargs) else: command = ' '.join(args) + ' ' + ' '.join(kwargs) log.info("torrserverd: starting without subprocess: %s" % command) return os.system(command)
def get_platform(): build = xbmc.getInfoLabel("System.BuildVersion") kodi_version = int(build.split()[0][:2]) ret = { "auto_arch": sys.maxsize > 2**32 and "64-bit" or "32-bit", "arch": sys.maxsize > 2**32 and "amd64" or "386", "os": "", "version": platform.release(), "kodi": kodi_version, "build": build, "fork": True, } if xbmc.getCondVisibility("system.platform.linux"): ret["os"] = "linux" if "aarch" in platform.machine().lower( ) or "arm64" in platform.machine().lower(): dump_version() if xbmc.getCondVisibility("system.platform.linux.raspberrypi"): ret["arch"] = "arm7" elif ret["auto_arch"] == "32-bit": ret["arch"] = "arm7" elif ret["auto_arch"] == "64-bit": ret["arch"] = "arm64" else: ret["arch"] = "arm7" elif "arm" in platform.machine(): dump_version() cpuarch = "" if "aarch" in platform.machine().lower( ) or "arm" in platform.machine().lower(): info = cpuinfo() for proc in info.keys(): log.info("CPU: %s=%s" % (proc, info[proc])) model = "" if "Processor" in info[proc]: model = info[proc]["Processor"].lower() elif "model name" in info[proc]: model = info[proc]["model name"].lower() if model: log.info("Exploring model: %s" % model) if "aarch" in model or "arm64" in model or "v8l" in model: cpuarch = "arm64" elif "armv7" in model or "v7l" in model: cpuarch = "arm7" break if cpuarch: log.info("Using CPU info arch: %s" % cpuarch) ret["arch"] = cpuarch else: ret["arch"] = "arm6" elif xbmc.getCondVisibility("system.platform.windows"): ret["os"] = "windows" if platform.machine().endswith('64'): ret["arch"] = "amd64" return ret
def get_torrserver_binary(): binary = "TorrServer-" + "%(os)s-%(arch)s" % PLATFORM + ( PLATFORM["os"] == "windows" and ".exe" or "") binary_dir = os.path.join(ADDON_PATH, "resources", "bin") if PLATFORM["os"] == "android": log.info("Detected binary folder: %s" % binary_dir) binary_dir_legacy = binary_dir.replace("/storage/emulated/0", "/storage/emulated/legacy") if os.path.exists(binary_dir_legacy): binary_dir = binary_dir_legacy log.info("Using changed binary folder for Android: %s" % binary_dir) app_id = android_get_current_appid() xbmc_data_path = os.path.join("/data", "data", app_id) if not os.path.exists(xbmc_data_path): log.info("%s path does not exist, so using %s as xbmc_data_path" % (xbmc_data_path, xbmc.translatePath("special://masterprofile/"))) xbmc_data_path = xbmc.translatePath("special://masterprofile/") dest_binary_dir = os.path.join(xbmc_data_path, "files", ADDON_ID, "bin") else: dest_binary_dir = os.path.join( xbmc.translatePath(ADDON.getAddonInfo("profile")).decode('utf-8'), "bin") binary_path = os.path.join(binary_dir, binary) dest_binary_path = os.path.join(dest_binary_dir, binary) log.info("Binary detection. Source: %s, Destination: %s" % (binary_path, dest_binary_path)) if not os.path.exists(binary_path) or ADDON.getSetting( "update_binaries") == "true": version = ADDON_VERSION if not ADDON.getSetting("git_version") == "": version = ADDON.getSetting("git_version") download = dialog_yesno( "LOCALIZE[30000];;" + "TorrServer-%(os)s-%(arch)s" % PLATFORM + " v%s" % version, "LOCALIZE[30007]") system_information() if download: try: download_binary( version, binary, os.path.join(os.path.join(ADDON_PATH, "resources", "bin"), binary)) notify(getLocalizedString(30001), time=3000) except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) notify("Binary Not Found", time=2000) if dialog_yesno( "Не удалось скачать файл. Тогда возможно попробуем открыть его из папки ??" ): bFile = xbmcgui.Dialog().browseSingle( 1, 'Выберете файл сервера ' + binary, 'files', binary) if bFile: shutil.copy(bFile, binary_path) notify(getLocalizedString(30001), time=3000) else: return False, False else: ADDON.setSetting("update_binaries", "false") database_path = getShortPath( os.path.join( xbmc.translatePath( ADDON.getAddonInfo("profile")).decode('utf-8'))) if not os.path.exists(database_path): os.mkdir(database_path) else: try: log.info( "Source directory (%s):\n%s" % (binary_dir, os.listdir(os.path.join(binary_dir, "..")))) log.info("Destination directory (%s):\n%s" % (dest_binary_dir, os.listdir(os.path.join(dest_binary_dir, "..")))) except Exception: pass return False, False if os.path.isdir(dest_binary_path): log.warning( "Destination path is a directory, expected previous binary file, removing..." ) try: shutil.rmtree(dest_binary_path) except Exception as e: log.error("Unable to remove destination path for update: %s" % e) system_information() return False, False if not os.path.exists(dest_binary_path) or not os.path.exists( binary_path) or get_torrserverd_checksum( dest_binary_path) != get_torrserverd_checksum( binary_path) or not filecmp.cmp( dest_binary_path, binary_path, shallow=True): log.info("Updating torrserver daemon...") try: os.makedirs(dest_binary_dir) except OSError: pass try: shutil.rmtree(dest_binary_dir) except Exception as e: log.error("Unable to remove destination path for update: %s" % e) system_information() pass try: if not os.path.exists(dest_binary_dir): os.mkdir(dest_binary_dir) shutil.copy(binary_path, dest_binary_path) except Exception as e: log.error("Unable to copy to destination path for update: %s" % e) system_information() return False, False # Clean stale files in the directory, as this can cause headaches on # Android when they are unreachable dest_files = set(os.listdir(dest_binary_dir)) orig_files = set(os.listdir(binary_dir)) log.info("Deleting stale files %s" % (dest_files - orig_files)) for file_ in (dest_files - orig_files): path = os.path.join(dest_binary_dir, file_) if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) log.info("Binary detection: [ Source: %s, Destination: %s ]" % (binary_path, dest_binary_path)) return dest_binary_dir, ensure_exec_perms(dest_binary_path)
def torrserverd_thread(monitor): crash_count = 0 try: while not xbmc.abortRequested: xbmc.log("torrserverd: starting torrserverd", level=xbmc.LOGNOTICE) proc = None if hasSubprocess: proc = start_torrserverd(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) if not proc: break else: start_torrserverd() threading.Thread(target=wait_for_abortRequested, args=[proc, monitor]).start() if not hasSubprocess: break if PLATFORM["os"] == "windows": while proc.poll() is None: log.info(proc.stdout.readline()) else: # Kodi hangs on some Android (sigh...) systems when doing a blocking # read. We count on the fact that torrserver daemon flushes its log # output on \n, creating a pretty clean output import fcntl import select fd = proc.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) while proc.poll() is None: try: to_read, _, _ = select.select([proc.stdout], [], []) for ro in to_read: line = ro.readline() if line == "": # write end is closed break log.info(line) except IOError: time.sleep(1) # nothing to read, sleep if xbmc.abortRequested: break if proc.returncode == 0: notify(getLocalizedString(30001), time=3000) else: crash_count += 1 notify(getLocalizedString(30002), time=3000) xbmc.executebuiltin("Dialog.Close(all, true)") system_information() time.sleep(5) if crash_count >= 3: notify(getLocalizedString(30003), time=3000) break except Exception as e: import traceback map(log.error, traceback.format_exc().split("\n")) notify("%s: %s" % (getLocalizedString(30004), repr(e).encode('utf-8'))) raise