summaryrefslogtreecommitdiffstats
path: root/module/remote
diff options
context:
space:
mode:
authorGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-03-23 21:56:42 +0100
committerGravatar RaNaN <Mast3rRaNaN@hotmail.de> 2013-03-23 21:56:42 +0100
commit6e8a0f79f5ad7182a0bc35308ae06c63222667ed (patch)
tree0026179d34f19b64bc689c63af85b949ce57fb83 /module/remote
parentshow button when files are selected (diff)
downloadpyload-6e8a0f79f5ad7182a0bc35308ae06c63222667ed.tar.xz
implemented interactions for multi user, show waiting queries on webui
Diffstat (limited to 'module/remote')
-rw-r--r--module/remote/apitypes.py38
-rw-r--r--module/remote/apitypes_debug.py16
-rw-r--r--module/remote/pyload.thrift34
-rw-r--r--module/remote/wsbackend/AsyncHandler.py20
4 files changed, 65 insertions, 43 deletions
diff --git a/module/remote/apitypes.py b/module/remote/apitypes.py
index 83368c6de..83eb19450 100644
--- a/module/remote/apitypes.py
+++ b/module/remote/apitypes.py
@@ -43,7 +43,7 @@ class FileStatus:
Missing = 1
Remote = 2
-class Input:
+class InputType:
NA = 0
Text = 1
Int = 2
@@ -58,6 +58,12 @@ class Input:
List = 11
Table = 12
+class Interaction:
+ All = 0
+ Notification = 1
+ Captcha = 2
+ Query = 4
+
class MediaType:
All = 0
Other = 1
@@ -67,12 +73,6 @@ class MediaType:
Document = 16
Archive = 32
-class Output:
- All = 0
- Notification = 1
- Captcha = 2
- Query = 4
-
class PackageStatus:
Ok = 0
Paused = 1
@@ -150,13 +150,13 @@ class ConfigInfo(BaseObject):
self.activated = activated
class ConfigItem(BaseObject):
- __slots__ = ['name', 'label', 'description', 'type', 'default_value', 'value']
+ __slots__ = ['name', 'label', 'description', 'input', 'default_value', 'value']
- def __init__(self, name=None, label=None, description=None, type=None, default_value=None, value=None):
+ def __init__(self, name=None, label=None, description=None, input=None, default_value=None, value=None):
self.name = name
self.label = label
self.description = description
- self.type = type
+ self.input = input
self.default_value = default_value
self.value = value
@@ -211,14 +211,20 @@ class FileInfo(BaseObject):
class Forbidden(ExceptionObject):
pass
+class Input(BaseObject):
+ __slots__ = ['type', 'data']
+
+ def __init__(self, type=None, data=None):
+ self.type = type
+ self.data = data
+
class InteractionTask(BaseObject):
- __slots__ = ['iid', 'input', 'data', 'output', 'default_value', 'title', 'description', 'plugin']
+ __slots__ = ['iid', 'type', 'input', 'default_value', 'title', 'description', 'plugin']
- def __init__(self, iid=None, input=None, data=None, output=None, default_value=None, title=None, description=None, plugin=None):
+ def __init__(self, iid=None, type=None, input=None, default_value=None, title=None, description=None, plugin=None):
self.iid = iid
+ self.type = type
self.input = input
- self.data = data
- self.output = output
self.default_value = default_value
self.title = title
self.description = description
@@ -438,12 +444,10 @@ class Iface(object):
pass
def getFilteredFiles(self, state):
pass
- def getInteractionTask(self, mode):
+ def getInteractionTasks(self, mode):
pass
def getLog(self, offset):
pass
- def getNotifications(self):
- pass
def getPackageContent(self, pid):
pass
def getPackageInfo(self, pid):
diff --git a/module/remote/apitypes_debug.py b/module/remote/apitypes_debug.py
index 4fab11f96..6909464d4 100644
--- a/module/remote/apitypes_debug.py
+++ b/module/remote/apitypes_debug.py
@@ -9,9 +9,9 @@ enums = [
"DownloadState",
"DownloadStatus",
"FileStatus",
- "Input",
+ "InputType",
+ "Interaction",
"MediaType",
- "Output",
"PackageStatus",
"Permission",
"Role",
@@ -23,21 +23,22 @@ classes = {
'AddonService' : [basestring, basestring, (list, basestring), (None, int)],
'ConfigHolder' : [basestring, basestring, basestring, basestring, (list, ConfigItem), (None, (list, AddonInfo)), (None, (list, InteractionTask))],
'ConfigInfo' : [basestring, basestring, basestring, basestring, bool, (None, bool)],
- 'ConfigItem' : [basestring, basestring, basestring, basestring, (None, basestring), basestring],
+ 'ConfigItem' : [basestring, basestring, basestring, Input, basestring, basestring],
'DownloadInfo' : [basestring, basestring, basestring, int, basestring, basestring],
'DownloadProgress' : [int, int, int, int],
'EventInfo' : [basestring, (list, basestring)],
'FileDoesNotExists' : [int],
'FileInfo' : [int, basestring, int, int, int, int, int, int, int, (None, DownloadInfo)],
- 'InteractionTask' : [int, int, (list, basestring), int, (None, basestring), basestring, basestring, basestring],
+ 'Input' : [int, (None, basestring)],
+ 'InteractionTask' : [int, int, Input, (None, basestring), basestring, basestring, basestring],
'InvalidConfigSection' : [basestring],
'LinkStatus' : [basestring, basestring, basestring, int, int, basestring],
- 'OnlineCheck' : [int, (dict, basestring, LinkStatus)],
+ 'OnlineCheck' : [int, (None, (dict, basestring, LinkStatus))],
'PackageDoesNotExists' : [int],
'PackageInfo' : [int, basestring, basestring, int, int, basestring, basestring, basestring, int, (list, basestring), int, bool, int, PackageStats, (list, int), (list, int)],
'PackageStats' : [int, int, int, int],
'ProgressInfo' : [basestring, basestring, basestring, int, int, int, (None, DownloadProgress)],
- 'ServerStatus' : [int, int, int, int, int, int, bool, bool, bool],
+ 'ServerStatus' : [int, int, int, int, int, bool, bool, bool, bool],
'ServiceDoesNotExists' : [basestring, basestring],
'ServiceException' : [basestring],
'TreeCollection' : [PackageInfo, (dict, int, FileInfo), (dict, int, PackageInfo)],
@@ -86,9 +87,8 @@ methods = {
'getFileTree': TreeCollection,
'getFilteredFileTree': TreeCollection,
'getFilteredFiles': TreeCollection,
- 'getInteractionTask': InteractionTask,
+ 'getInteractionTasks': (list, InteractionTask),
'getLog': (list, basestring),
- 'getNotifications': (list, InteractionTask),
'getPackageContent': TreeCollection,
'getPackageInfo': PackageInfo,
'getPluginConfig': (list, ConfigInfo),
diff --git a/module/remote/pyload.thrift b/module/remote/pyload.thrift
index 06add4208..76e755de0 100644
--- a/module/remote/pyload.thrift
+++ b/module/remote/pyload.thrift
@@ -69,7 +69,7 @@ enum PackageStatus {
// some may only be place holder currently not supported
// also all input - output combination are not reasonable, see InteractionManager for further info
// Todo: how about: time, ip, s.o.
-enum Input {
+enum InputType {
NA,
Text,
Int,
@@ -88,7 +88,7 @@ enum Input {
// this describes the type of the outgoing interaction
// ensure they can be logcial or'ed
-enum Output {
+enum Interaction {
All = 0,
Notification = 1,
Captcha = 2,
@@ -111,6 +111,11 @@ enum Role {
User = 1
}
+struct Input {
+ 1: InputType type,
+ 2: optional JSONString data,
+}
+
struct DownloadProgress {
1: FileID fid,
2: PackageID pid,
@@ -200,7 +205,7 @@ struct ServerStatus {
3: i16 linksqueue,
4: ByteCount sizetotal,
5: ByteCount sizequeue,
- 6: i16 notifications,
+ 6: bool notifications,
7: bool paused,
8: bool download,
9: bool reconnect,
@@ -208,13 +213,12 @@ struct ServerStatus {
struct InteractionTask {
1: InteractionID iid,
- 2: Input input,
- 3: list<string> data,
- 4: Output output,
- 5: optional JSONString default_value,
- 6: string title,
- 7: string description,
- 8: PluginName plugin,
+ 2: Interaction type,
+ 3: Input input,
+ 4: optional JSONString default_value,
+ 5: string title,
+ 6: string description,
+ 7: PluginName plugin,
}
struct AddonService {
@@ -234,7 +238,7 @@ struct ConfigItem {
1: string name,
2: string label,
3: string description,
- 4: string type,
+ 4: Input input,
5: JSONString default_value,
6: JSONString value,
}
@@ -360,7 +364,7 @@ service Pyload {
map<string, ConfigHolder> getConfig(),
string getConfigValue(1: string section, 2: string option),
- // two methods with ambigous classification, could be configuration or addon related
+ // two methods with ambigous classification, could be configuration or addon/plugin related
list<ConfigInfo> getCoreConfig(),
list<ConfigInfo> getPluginConfig(),
list<ConfigInfo> getAvailablePlugins(),
@@ -473,16 +477,14 @@ service Pyload {
// User Interaction
///////////////////////
- // mode = Output types binary ORed
+ // mode = interaction types binary ORed
bool isInteractionWaiting(1: i16 mode),
- InteractionTask getInteractionTask(1: i16 mode),
+ list<InteractionTask> getInteractionTasks(1: i16 mode),
void setInteractionResult(1: InteractionID iid, 2: JSONString result),
// generate a download link, everybody can download the file until timeout reached
string generateDownloadLink(1: FileID fid, 2: i16 timeout),
- list<InteractionTask> getNotifications(),
-
///////////////////////
// Account Methods
///////////////////////
diff --git a/module/remote/wsbackend/AsyncHandler.py b/module/remote/wsbackend/AsyncHandler.py
index 99ffe9894..b40f0ea4e 100644
--- a/module/remote/wsbackend/AsyncHandler.py
+++ b/module/remote/wsbackend/AsyncHandler.py
@@ -23,7 +23,7 @@ from time import time
from mod_pywebsocket.msgutil import receive_message
-from module.Api import EventInfo
+from module.Api import EventInfo, Interaction
from module.utils import lock
from AbstractHandler import AbstractHandler
@@ -44,7 +44,8 @@ class AsyncHandler(AbstractHandler):
COMMAND = "start"
PROGRESS_INTERVAL = 2
- EVENT_PATTERN = re.compile(r"^(package|file)", re.I)
+ EVENT_PATTERN = re.compile(r"^(package|file|interaction)", re.I)
+ INTERACTION = Interaction.All
def __init__(self, api):
AbstractHandler.__init__(self, api)
@@ -58,6 +59,7 @@ class AsyncHandler(AbstractHandler):
req.queue = Queue()
req.interval = self.PROGRESS_INTERVAL
req.events = self.EVENT_PATTERN
+ req.interaction = self.INTERACTION
req.mode = Mode.STANDBY
req.t = time() # time when update should be pushed
self.clients.append(req)
@@ -76,6 +78,18 @@ class AsyncHandler(AbstractHandler):
event = EventInfo(event, [x.toInfoData() if hasattr(x, 'toInfoData') else x for x in args])
for req in self.clients:
+ # filter events that these user is no owner of
+ # TODO: events are security critical, this should be revised later
+ if not req.api.user.isAdmin():
+ skip = False
+ for arg in args:
+ if hasattr(arg, 'owner') and arg.owner != req.api.primaryUID:
+ skip = True
+ break
+
+ # user should not get this event
+ if skip: break
+
if req.events.search(event.eventname):
self.log.debug("Pushing event %s" % event)
req.queue.put(event)
@@ -115,6 +129,8 @@ class AsyncHandler(AbstractHandler):
req.interval = args[0]
elif func == "setEvents":
req.events = re.compile(args[0], re.I)
+ elif func == "setInteraction":
+ req.interaction = args[0]
elif func == self.COMMAND:
req.mode = Mode.RUNNING