Formatting

This commit is contained in:
James Barnsley
2020-02-03 16:48:39 +13:00
parent df18eba73c
commit b789d322b3
5 changed files with 269 additions and 127 deletions

View File

@ -1,4 +1,6 @@
import logging, json, pathlib
import logging
import json
import pathlib
import pkg_resources
from mopidy import config, ext
@ -37,7 +39,9 @@ class Extension(ext.Extension):
from .frontend import IrisFrontend
# Add web extension
registry.add("http:app", {"name": self.ext_name, "factory": iris_factory})
registry.add(
"http:app", {
"name": self.ext_name, "factory": iris_factory})
# Add our frontend
registry.add("frontend", IrisFrontend)

View File

@ -1,13 +1,18 @@
import random, string, logging, json, pathlib, pykka, urllib, os, sys, mopidy_iris, subprocess
import random
import string
import logging
import json
import pathlib
import pykka
import urllib
import os
import sys
import tornado.web
import tornado.ioloop
import requests
import time
import pickle
from mopidy import config, ext
from mopidy.core import CoreListener
from pkg_resources import parse_version
from tornado.escape import json_encode, json_decode
from tornado.escape import json_encode
from tornado.httpclient import AsyncHTTPClient, HTTPRequest
from pathlib import Path
@ -75,7 +80,7 @@ class IrisCore(pykka.ThreadingActor):
content = pickle.load(f)
f.close()
return content
except Exception as e:
except Exception:
return {}
##
@ -114,7 +119,8 @@ class IrisCore(pykka.ThreadingActor):
# @return string
##
def generateGuid(self):
return "".join(random.choices(string.ascii_uppercase + string.digits, k=12))
return "".join(random.choices(
string.ascii_uppercase + string.digits, k=12))
##
# Digest a protocol header into it's id/name parts
@ -124,10 +130,12 @@ class IrisCore(pykka.ThreadingActor):
def digest_protocol(self, protocol):
# if we're a string, split into list
# this handles the different ways we get this passed (select_subprotocols gives string, headers.get gives list)
if isinstance(protocol, basestring):
# this handles the different ways we get this passed
# (select_subprotocols gives string, headers.get gives list)
if isinstance(protocol, str):
# make sure we strip any spaces (IE gives "element,element", proper browsers give "element, element")
# make sure we strip any spaces (IE gives "element,element", proper
# browsers give "element, element")
protocol = [i.strip() for i in protocol.split(",")]
# if we've been given a valid array
@ -138,7 +146,7 @@ class IrisCore(pykka.ThreadingActor):
generated = False
# invalid, so just create a default connection, and auto-generate an ID
except:
except BaseException:
client_id = self.generateGuid()
connection_id = self.generateGuid()
username = "Anonymous"
@ -197,7 +205,7 @@ class IrisCore(pykka.ThreadingActor):
callback(response)
else:
return response
except:
except BaseException:
error = "Failed to send message to " + data["recipient"]
logger.error(error)
@ -234,9 +242,8 @@ class IrisCore(pykka.ThreadingActor):
if send_to_this_connection:
connection["connection"].write_message(json_encode(message))
response = {
"message": "Broadcast to " + str(len(self.connections)) + " connections"
}
response = {"message": "Broadcast to " +
str(len(self.connections)) + " connections"}
if callback:
callback(response)
else:
@ -245,9 +252,9 @@ class IrisCore(pykka.ThreadingActor):
##
# Connections
#
# Contains all our connections and client details. This requires updates
# when new clients connect, and old ones disconnect. These events are broadcast
# to all current connections
# Contains all our connections and client details. This requires
# updates when new clients connect, and old ones disconnect. These
# events are broadcast to all current connections
##
def get_connections(self, *args, **kwargs):
@ -277,7 +284,10 @@ class IrisCore(pykka.ThreadingActor):
}
self.broadcast(
data={"method": "connection_added", "params": {"connection": client}}
data={
"method": "connection_added",
"params": {
"connection": client}}
)
def update_connection(self, *args, **kwargs):
@ -286,15 +296,19 @@ class IrisCore(pykka.ThreadingActor):
connection_id = data["connection_id"]
if connection_id in self.connections:
self.connections[connection_id]["client"]["username"] = data["username"]
self.connections[connection_id]["client"]["client_id"] = data["client_id"]
username = data["username"]
client_id = data["client_id"]
self.connections[connection_id]["client"]["username"] = username
self.connections[connection_id]["client"]["client_id"] = client_id
self.broadcast(
data={
"method": "connection_changed",
"params": {"connection": self.connections[connection_id]["client"]},
}
)
response = {"connection": self.connections[connection_id]["client"]}
"params": {
"connection":
self.connections[connection_id]["client"]},
})
response = {
"connection": self.connections[connection_id]["client"]}
if callback:
callback(response)
else:
@ -321,7 +335,7 @@ class IrisCore(pykka.ThreadingActor):
"params": {"connection": client},
}
)
except:
except BaseException:
logger.error("Failed to close connection to " + connection_id)
def set_username(self, *args, **kwargs):
@ -330,14 +344,18 @@ class IrisCore(pykka.ThreadingActor):
connection_id = data["connection_id"]
if connection_id in self.connections:
self.connections[connection_id]["client"]["username"] = data["username"]
username = data["username"]
self.connections[connection_id]["client"]["username"] = username
self.broadcast(
data={
"method": "connection_changed",
"params": {"connection": self.connections[connection_id]["client"]},
}
)
response = {"connection_id": connection_id, "username": data["username"]}
"params": {
"connection":
self.connections[connection_id]["client"]},
})
response = {
"connection_id": connection_id,
"username": data["username"]}
if callback:
callback(response)
else:
@ -363,7 +381,8 @@ class IrisCore(pykka.ThreadingActor):
callback = kwargs.get("callback", False)
# handle config setups where there is no username/password
# Iris won't work properly anyway, but at least we won't get server errors
# Iris won't work properly anyway, but at least we won't get server
# errors
if "spotify" in self.config and "username" in self.config["spotify"]:
spotify_username = self.config["spotify"]["username"]
else:
@ -410,7 +429,7 @@ class IrisCore(pykka.ThreadingActor):
)
upgrade_available = upgrade_available == 1
except (urllib.request.HTTPError, urllib.request.URLError) as e:
except (urllib.request.HTTPError, urllib.request.URLError):
latest_version = "0.0.0"
upgrade_available = False
@ -450,9 +469,15 @@ class IrisCore(pykka.ThreadingActor):
if error:
self.broadcast(data={"method": "restart_error", "params": error})
elif update:
self.broadcast(data={"method": "restart_updated", "params": update})
self.broadcast(
data={
"method": "restart_updated",
"params": update})
else:
self.broadcast(data={"method": "restart_finished", "params": response})
self.broadcast(
data={
"method": "restart_finished",
"params": response})
##
# Run an upgrade of Iris
@ -477,9 +502,15 @@ class IrisCore(pykka.ThreadingActor):
if error:
self.broadcast(data={"method": "upgrade_error", "params": error})
elif update:
self.broadcast(data={"method": "upgrade_updated", "params": update})
self.broadcast(
data={
"method": "upgrade_updated",
"params": update})
else:
self.broadcast(data={"method": "upgrade_finished", "params": response})
self.broadcast(
data={
"method": "upgrade_finished",
"params": response})
self.restart()
##
@ -491,7 +522,10 @@ class IrisCore(pykka.ThreadingActor):
ioloop = kwargs.get("ioloop", False)
# Trigger the action
IrisSystemThread("local_scan", ioloop, self.local_scan_callback).start()
IrisSystemThread(
"local_scan",
ioloop,
self.local_scan_callback).start()
self.broadcast(data={"method": "local_scan_started"})
@ -503,18 +537,28 @@ class IrisCore(pykka.ThreadingActor):
def local_scan_callback(self, response, error, update):
if error:
self.broadcast(data={"method": "local_scan_error", "params": error})
self.broadcast(
data={
"method": "local_scan_error",
"params": error})
elif update:
self.broadcast(data={"method": "local_scan_updated", "params": update})
self.broadcast(
data={
"method": "local_scan_updated",
"params": update})
else:
self.broadcast(data={"method": "local_scan_finished", "params": response})
self.broadcast(
data={
"method": "local_scan_finished",
"params": response})
##
# Spotify Radio
#
# Accepts seed URIs and creates radio-like experience. When our tracklist is nearly
# empty, we fetch more recommendations. This can result in duplicates. We keep the
# recommendations limit low to avoid timeouts and slow UI
# Accepts seed URIs and creates radio-like experience. When our
# tracklist is nearly empty, we fetch more recommendations. This
# can result in duplicates. We keep the recommendations limit low
# to avoid timeouts and slow UI
##
def get_radio(self, *args, **kwargs):
@ -578,11 +622,17 @@ class IrisCore(pykka.ThreadingActor):
if starting:
self.core.playback.play()
self.broadcast(
data={"method": "radio_started", "params": {"radio": self.radio}}
data={
"method": "radio_started",
"params": {
"radio": self.radio}}
)
else:
self.broadcast(
data={"method": "radio_changed", "params": {"radio": self.radio}}
data={
"method": "radio_changed",
"params": {
"radio": self.radio}}
)
self.get_radio(callback=callback)
@ -632,7 +682,7 @@ class IrisCore(pykka.ThreadingActor):
await self.get_spotify_token()
spotify_token = self.spotify_token
access_token = spotify_token["access_token"]
except:
except BaseException:
error = "IrisFrontend: access_token missing or invalid"
logger.error(error)
return False
@ -641,24 +691,29 @@ class IrisCore(pykka.ThreadingActor):
url = (
url
+ "?seed_artists="
+ (",".join(self.radio["seed_artists"])).replace("spotify:artist:", "")
+ (",".join(self.radio["seed_artists"])
).replace("spotify:artist:", "")
)
url = (
url
+ "&seed_genres="
+ (",".join(self.radio["seed_genres"])).replace("spotify:genre:", "")
+ (",".join(self.radio["seed_genres"])
).replace("spotify:genre:", "")
)
url = (
url
+ "&seed_tracks="
+ (",".join(self.radio["seed_tracks"])).replace("spotify:track:", "")
+ (",".join(self.radio["seed_tracks"])
).replace("spotify:track:", "")
)
url = url + "&limit=50"
http_client = AsyncHTTPClient()
try:
http_response = await http_client.fetch(
url, "POST", headers={"Authorization": "Bearer " + access_token}
url, "POST", headers={
"Authorization": "Bearer " + access_token
}
)
response_body = json.loads(http_response.body)
@ -675,7 +730,8 @@ class IrisCore(pykka.ThreadingActor):
+ error["error_description"]
}
logger.error(
"Could not fetch Spotify recommendations: " + error["error_description"]
"Could not fetch Spotify recommendations: " +
error["error_description"]
)
logger.debug(error)
return False
@ -687,7 +743,8 @@ class IrisCore(pykka.ThreadingActor):
# Grab our loaded tracks
uris = self.radio["results"]
# We've run out of pre-fetched tracks, so we need to get more recommendations
# We've run out of pre-fetched tracks, so we need to get more
# recommendations
if len(uris) < 3:
uris = self.load_more_tracks()
@ -753,8 +810,10 @@ class IrisCore(pykka.ThreadingActor):
for tlid in data["tlids"]:
item = {
"tlid": tlid,
"added_from": data["added_from"] if "added_from" in data else None,
"added_by": data["added_by"] if "added_by" in data else None,
"added_from":
data["added_from"] if "added_from" in data else None,
"added_by":
data["added_by"] if "added_by" in data else None,
}
self.queue_metadata["tlid_" + str(tlid)] = item
@ -772,12 +831,12 @@ class IrisCore(pykka.ThreadingActor):
return response
def clean_queue_metadata(self, *args, **kwargs):
callback = kwargs.get("callback", False)
cleaned_queue_metadata = {}
for tltrack in self.core.tracklist.get_tl_tracks().get():
# if we have metadata for this track, push it through to cleaned dictionary
# if we have metadata for this track, push it through to cleaned
# dictionary
if "tlid_" + str(tltrack.tlid) in self.queue_metadata:
cleaned_queue_metadata[
"tlid_" + str(tltrack.tlid)
@ -811,7 +870,10 @@ class IrisCore(pykka.ThreadingActor):
self.save_to_file(self.commands, "commands")
self.broadcast(
data={"method": "commands_changed", "params": {"commands": self.commands}}
data={
"method": "commands_changed",
"params": {
"commands": self.commands}}
)
response = {"message": "Commands saved"}
@ -822,14 +884,14 @@ class IrisCore(pykka.ThreadingActor):
async def run_command(self, *args, **kwargs):
callback = kwargs.get("callback", False)
ioloop = kwargs.get("ioloop", False)
data = kwargs.get("data", {})
error = False
if str(data["id"]) not in self.commands:
error = {
"message": "Command failed",
"description": 'Could not find command by ID "' + str(data["id"]) + '"',
"description": r'''Could not find command by ID
"' + str(data["id"]) + '"''',
}
else:
command = self.commands[str(data["id"])]
@ -859,7 +921,8 @@ class IrisCore(pykka.ThreadingActor):
d = command["additional_headers"].split("\n")
lines = list(filter(lambda x: x.find(":") > 0, d))
fields = [
(x.split(":", 1)[0].strip().lower(), x.split(":", 1)[1].strip())
(x.split(":", 1)[0].strip().lower(),
x.split(":", 1)[1].strip())
for x in lines
]
headers = dict(fields)
@ -882,8 +945,10 @@ class IrisCore(pykka.ThreadingActor):
)
else:
request = HTTPRequest(
command["url"], connect_timeout=5, validate_cert=False, headers=headers
)
command["url"],
connect_timeout=5,
validate_cert=False,
headers=headers)
# Make the request, and handle any request errors
try:
@ -900,15 +965,18 @@ class IrisCore(pykka.ThreadingActor):
# Attempt to parse body as JSON
try:
command_response_body = json.loads(command_response.body)
except:
except BaseException:
# Perhaps it requires unicode encoding?
try:
command_response_body = tornado.escape.to_unicode(command_response.body)
except:
command_response_body = tornado.escape.to_unicode(
command_response.body)
except BaseException:
command_response_body = ""
# Finally, return the result
response = {"message": "Command run", "response": command_response_body}
response = {
"message": "Command run",
"response": command_response_body}
if callback:
callback(response)
@ -919,16 +987,20 @@ class IrisCore(pykka.ThreadingActor):
##
# Spotify authentication
#
# Uses the Client Credentials Flow, so is invisible to the user. We need this token for
# any backend spotify requests (we don't tap in to Mopidy-Spotify, yet). Also used for
# passing token to frontend for javascript requests without use of the Authorization Code Flow.
# Uses the Client Credentials Flow, so is invisible to the user.
# We need this token for any backend spotify requests (we don't tap in
# to Mopidy-Spotify, yet). Also used for passing token to frontend for
# javascript requests without use of the Authorization Code Flow.
##
async def get_spotify_token(self, *args, **kwargs):
callback = kwargs.get("callback", False)
# Expired, so go get a new one
if not self.spotify_token or self.spotify_token["expires_at"] <= time.time():
if (
not self.spotify_token or
self.spotify_token["expires_at"] <= time.time()
):
await self.refresh_spotify_token()
response = {"spotify_token": self.spotify_token}
@ -977,8 +1049,8 @@ class IrisCore(pykka.ThreadingActor):
except (urllib.error.HTTPError, urllib.error.URLError) as e:
error = json.loads(e.read())
error = {
"message": "Could not refresh token: " + error["error_description"]
}
"message": "Could not refresh token: " +
error["error_description"]}
if callback:
callback(False, error)
@ -997,9 +1069,10 @@ class IrisCore(pykka.ThreadingActor):
##
# Spotify authentication
#
# Uses the Client Credentials Flow, so is invisible to the user. We need this token for
# any backend spotify requests (we don't tap in to Mopidy-Spotify, yet). Also used for
# passing token to frontend for javascript requests without use of the Authorization Code Flow.
# Uses the Client Credentials Flow, so is invisible to the user.
# We need this token for any backend spotify requests (we don't tap in
# to Mopidy-Spotify, yet). Also used for passing token to frontend for
# javascript requests without use of the Authorization Code Flow.
##
async def get_lyrics(self, *args, **kwargs):
@ -1021,7 +1094,9 @@ class IrisCore(pykka.ThreadingActor):
if connection_id not in self.connections:
error = {
"message": "Unauthorized request",
"description": "Connection " + connection_id + " not connected",
"description": "Connection " +
connection_id +
" not connected",
}
except Exception as e:
@ -1037,7 +1112,11 @@ class IrisCore(pykka.ThreadingActor):
try:
http_client = AsyncHTTPClient()
http_response = await http_client.fetch(url)
callback(http_response.body.decode("utf-8", errors="replace"), False)
callback(
http_response.body.decode(
"utf-8",
errors="replace"),
False)
except (urllib.error.HTTPError, urllib.error.URLError) as e:
error = json.loads(e.read())
@ -1046,7 +1125,8 @@ class IrisCore(pykka.ThreadingActor):
+ error["error_description"]
}
logger.error(
"Could not fetch Spotify recommendations: " + error["error_description"]
"Could not fetch Spotify recommendations: " +
error["error_description"]
)
logger.debug(error)
return error
@ -1075,4 +1155,7 @@ class IrisCore(pykka.ThreadingActor):
elif error:
self.broadcast(data={"method": "test_updated", "params": update})
else:
self.broadcast(data={"method": "test_finished", "params": response})
self.broadcast(
data={
"method": "test_finished",
"params": response})

View File

@ -1,6 +1,7 @@
import pykka, logging, tornado, functools
import pykka
import logging
import functools
from mopidy.core import CoreListener
from .core import IrisCore
from .mem import iris
# import logger
@ -22,7 +23,9 @@ class IrisFrontend(pykka.ThreadingActor, CoreListener):
iris.stop()
def track_playback_ended(self, tl_track, time_position):
iris.ioloop.add_callback(functools.partial(iris.check_for_radio_update))
iris.ioloop.add_callback(
functools.partial(
iris.check_for_radio_update))
def tracklist_changed(self):
iris.ioloop.add_callback(functools.partial(iris.clean_queue_metadata))

View File

@ -1,7 +1,13 @@
from datetime import datetime
from tornado.escape import json_encode, json_decode
import tornado.ioloop, tornado.web, tornado.websocket, tornado.template
import random, string, logging, uuid, subprocess, pykka, ast, logging, json, urllib, requests, time, asyncio
import tornado.ioloop
import tornado.web
import tornado.websocket
import tornado.template
import logging
import json
import time
import asyncio
from .mem import iris
@ -24,10 +30,12 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
# Get the client's IP. If it's local, then use it's proxy origin
ip = self.request.remote_ip
if ip == "127.0.0.1" and hasattr(self.request.headers, "X-Forwarded-For"):
if ip == "127.0.0.1" and hasattr(
self.request.headers, "X-Forwarded-For"):
ip = self.request.headers["X-Forwarded-For"]
# Construct our initial client object, and add to our list of connections
# Construct our initial client object, and add to our list of
# connections
client = {
"connection_id": iris.generateGuid(),
"ip": ip,
@ -54,7 +62,8 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
error={
"id": id,
"code": 32602,
"message": 'Invalid JSON-RPC request (missing property "jsonrpc")',
"message": r'''Invalid JSON-RPC request (missing
property "jsonrpc")''',
},
)
@ -75,12 +84,15 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
if hasattr(iris, message["method"]):
try:
# For async methods we need to await, but it must be ommited for syncronous methods
if asyncio.iscoroutinefunction(getattr(iris, message["method"])):
# For async methods we need to await, but it must be
# ommited for syncronous methods
if asyncio.iscoroutinefunction(
getattr(iris, message["method"])):
await getattr(iris, message["method"])(
ioloop=self.ioloop,
data=params,
callback=lambda response, error=False: self.handle_result(
callback=lambda response,
error=False: self.handle_result(
id=id,
method=message["method"],
response=response,
@ -88,10 +100,13 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
),
)
else:
getattr(iris, message["method"])(
getattr(
iris,
message["method"])(
ioloop=self.ioloop,
data=params,
callback=lambda response, error=False: self.handle_result(
callback=lambda response,
error=False: self.handle_result(
id=id,
method=message["method"],
response=response,
@ -106,7 +121,9 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
error={
"id": id,
"code": 32601,
"message": 'Method "' + message["method"] + '" does not exist',
"message": 'Method "' +
message["method"] +
'" does not exist',
},
id=id,
)
@ -142,7 +159,8 @@ class WebsocketHandler(tornado.websocket.WebSocketHandler):
request_response["error"] = error
# We've been handed an AsyncHTTPClient callback. This is the case
# when our request calls subsequent external requests (eg Spotify, Genius)
# when our request calls subsequent external requests (eg Spotify,
# Genius)
elif isinstance(response, tornado.httpclient.HTTPResponse):
request_response["result"] = response.body
@ -161,7 +179,8 @@ class HttpHandler(tornado.web.RequestHandler):
self.set_header("Access-Control-Allow-Origin", "*")
self.set_header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, Client-Security-Token, Accept-Encoding",
r'''Origin, X-Requested-With, Content-Type, Accept,
Authorization, Client-Security-Token, Accept-Encoding''',
)
def initialize(self, core, config):
@ -183,21 +202,29 @@ class HttpHandler(tornado.web.RequestHandler):
if hasattr(iris, slug):
try:
# For async methods we need to await, but it must be ommited for syncronous methods
# For async methods we need to await, but it must be ommited
# for syncronous methods
if asyncio.iscoroutinefunction(getattr(iris, slug)):
await getattr(iris, slug)(
ioloop=self.ioloop,
request=self,
callback=lambda response, error=False: self.handle_result(
callback=lambda response,
error=False: self.handle_result(
id=id, method=slug, response=response, error=error
),
)
else:
getattr(iris, slug)(
getattr(
iris,
slug)(
ioloop=self.ioloop,
request=self,
callback=lambda response, error=False: self.handle_result(
id=id, method=slug, response=response, error=error
callback=lambda response,
error=False: self.handle_result(
id=id,
method=slug,
response=response,
error=error
),
)
except Exception as e:
@ -206,7 +233,11 @@ class HttpHandler(tornado.web.RequestHandler):
else:
self.handle_result(
id=id,
error={"code": 32601, "message": "Method " + slug + " does not exist"},
error={
"code": 32601,
"message": "Method " +
slug +
" does not exist"},
)
return
@ -216,9 +247,10 @@ class HttpHandler(tornado.web.RequestHandler):
try:
params = json.loads(self.request.body.decode("utf-8"))
except:
except BaseException:
self.handle_result(
id=id, error={"code": 32700, "message": "Missing or invalid payload"}
id=id, error={
"code": 32700, "message": "Missing or invalid payload"}
)
return
@ -229,29 +261,41 @@ class HttpHandler(tornado.web.RequestHandler):
await getattr(iris, slug)(
data=params,
request=self.request,
callback=lambda response=False, error=False: self.handle_result(
callback=lambda response=False,
error=False: self.handle_result(
id=id, method=slug, response=response, error=error
),
)
else:
getattr(iris, slug)(
getattr(
iris,
slug)(
data=params,
request=self.request,
callback=lambda response=False, error=False: self.handle_result(
id=id, method=slug, response=response, error=error
callback=lambda response=False,
error=False: self.handle_result(
id=id,
method=slug,
response=response,
error=error
),
)
except tornado.web.HTTPError as e:
except tornado.web.HTTPError:
self.handle_result(
id=id, error={"code": 32601, "message": "Invalid JSON payload"}
id=id, error={
"code": 32601, "message": "Invalid JSON payload"}
)
return
else:
self.handle_result(
id=id,
error={"code": 32601, "message": "Method " + slug + " does not exist"},
error={
"code": 32601,
"message": "Method " +
slug +
" does not exist"},
)
return
@ -271,15 +315,17 @@ class HttpHandler(tornado.web.RequestHandler):
self.set_status(400)
# We've been handed an AsyncHTTPClient callback. This is the case
# when our request calls subsequent external requests (eg Spotify, Genius).
# when our request calls subsequent external requests.
# We don't need to wrap non-HTTPResponse responses as these are dicts
elif isinstance(response, tornado.httpclient.HTTPResponse):
# Digest JSON responses into JSON
content_type = response.headers.get("Content-Type")
if content_type.startswith("application/json") or content_type.startswith(
"text/json"
):
if content_type.startswith(
"application/json"
) or content_type.startswith(
"text/json"
):
body = json.loads(response.body)
# Non-JSON so just copy as-is

View File

@ -1,5 +1,8 @@
from threading import Thread
import logging, os, pathlib, subprocess, json, sys
import logging
import os
import pathlib
import subprocess
# import logger
logger = logging.getLogger(__name__)
@ -14,9 +17,9 @@ class IrisSystemPermissionError(IrisSystemError):
def __init__(self, path):
message = (
"Password-less access to %s was refused. Check your /etc/sudoers file."
% path.as_uri()
)
r'''Password-less access to %s was refused.
Check your /etc/sudoers file.''' %
path.as_uri())
logger.error(message)
super().__init__(message)
@ -63,7 +66,8 @@ class IrisSystemThread(Thread):
command = self.get_command()
logger.debug("Running '%s'", os.fsdecode(b" ".join(command)))
process = subprocess.Popen(command, stdout=subprocess.PIPE, encoding="utf8")
process = subprocess.Popen(
command, stdout=subprocess.PIPE, encoding="utf8")
lines = ""
while True:
@ -73,8 +77,6 @@ class IrisSystemThread(Thread):
if line:
logger.info(line)
lines = lines + "\n" + line
# This seems to be ignored. Detected as spammy io?
# self.ioloop.add_callback(lambda: self.callback(None, None, {'output': line}))
if process.returncode == 0:
self.ioloop.add_callback(
@ -92,10 +94,14 @@ class IrisSystemThread(Thread):
##
def can_run(self, *args, **kwargs):
# Attempt an empty call to our system file
command_bytes = b" ".join(self.get_command("check", non_interactive=True))
command_bytes = b" ".join(
self.get_command(
"check", non_interactive=True))
process = subprocess.Popen(
command_bytes, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
)
command_bytes,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=True)
result, error = process.communicate()
exitCode = process.wait()