Event fixes
This commit is contained in:
@@ -15,7 +15,7 @@ import os
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
app = Flask(__name__)
|
||||
app = Flask(__name__, static_folder = 'nope')
|
||||
web = Blueprint('web', __name__)
|
||||
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ class Core(Plugin):
|
||||
|
||||
def crappyShutdown(self):
|
||||
try:
|
||||
self.urlopen('%sapp.shutdown' % self.createApiUrl(), show_error = False)
|
||||
self.urlopen('%s/app.shutdown' % self.createApiUrl(), show_error = False)
|
||||
return True
|
||||
except:
|
||||
self.initShutdown()
|
||||
@@ -78,7 +78,7 @@ class Core(Plugin):
|
||||
|
||||
def crappyRestart(self):
|
||||
try:
|
||||
self.urlopen('%sapp.restart' % self.createApiUrl(), show_error = False)
|
||||
self.urlopen('%s/app.restart' % self.createApiUrl(), show_error = False)
|
||||
return True
|
||||
except:
|
||||
self.initShutdown(restart = True)
|
||||
@@ -163,8 +163,7 @@ class Core(Plugin):
|
||||
host = 'localhost'
|
||||
port = Env.setting('port')
|
||||
|
||||
return '%s:%d' % (cleanHost(host).rstrip('/'), int(port))
|
||||
return '%s:%d%s' % (cleanHost(host).rstrip('/'), int(port), '/' + Env.setting('url_base').lstrip('/') if Env.setting('url_base') else '')
|
||||
|
||||
def createApiUrl(self):
|
||||
|
||||
return '%s/%s/' % (self.createBaseUrl(), Env.setting('api_key'))
|
||||
return '%s/%s' % (self.createBaseUrl(), Env.setting('api_key'))
|
||||
|
||||
@@ -17,7 +17,7 @@ def requires_auth(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
auth = getattr(request, 'authorization')
|
||||
if Env.setting('username') and (not auth or not check_auth(auth.username, md5(auth.password))):
|
||||
if Env.setting('username') and Env.setting('password') and (not auth or not check_auth(auth.username, md5(auth.password))):
|
||||
return authenticate()
|
||||
|
||||
return f(*args, **kwargs)
|
||||
|
||||
@@ -2,6 +2,7 @@ from axl.axel import Event
|
||||
from couchpotato.core.helpers.variable import mergeDicts
|
||||
from couchpotato.core.logger import CPLog
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
|
||||
log = CPLog(__name__)
|
||||
@@ -25,15 +26,17 @@ def addEvent(name, handler, priority = 100):
|
||||
|
||||
try:
|
||||
parent = handler.im_self
|
||||
parent.beforeCall(handler)
|
||||
bc = hasattr(parent, 'beforeCall')
|
||||
if bc: parent.beforeCall(handler)
|
||||
h = runHandler(name, handler, *args, **kwargs)
|
||||
parent.afterCall(handler)
|
||||
ac = hasattr(parent, 'afterCall')
|
||||
if ac: parent.afterCall(handler)
|
||||
except:
|
||||
h = runHandler(name, handler, *args, **kwargs)
|
||||
|
||||
return h
|
||||
|
||||
e.handle(createHandle, priority = priority)
|
||||
e.handle(handler, priority = priority)
|
||||
|
||||
def removeEvent(name, handler):
|
||||
e = events[name]
|
||||
@@ -64,8 +67,10 @@ def fireEvent(name, *args, **kwargs):
|
||||
except: pass
|
||||
|
||||
e = events[name]
|
||||
e.lock.acquire()
|
||||
e.asynchronous = False
|
||||
result = e(*args, **kwargs)
|
||||
e.lock.release()
|
||||
|
||||
if single and not merge:
|
||||
results = None
|
||||
@@ -123,10 +128,11 @@ def fireEventAsync(name, *args, **kwargs):
|
||||
#log.debug('Async "%s": %s, %s' % (name, args, kwargs))
|
||||
try:
|
||||
e = events[name]
|
||||
e.lock.acquire()
|
||||
e.asynchronous = True
|
||||
e.error_handler = errorHandler
|
||||
|
||||
e(*args, **kwargs)
|
||||
e.lock.release()
|
||||
return True
|
||||
except Exception, e:
|
||||
log.error('%s: %s' % (name, e))
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
from couchpotato.core.event import fireEvent
|
||||
from couchpotato.core.logger import CPLog
|
||||
from couchpotato.core.notifications.base import Notification
|
||||
from gntp import notifier
|
||||
import logging
|
||||
import thread
|
||||
import time
|
||||
import traceback
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
@@ -15,13 +19,19 @@ class Growl(Notification):
|
||||
logger.disabled = True
|
||||
|
||||
try:
|
||||
self.growl = notifier.GrowlNotifier(
|
||||
applicationName = 'CouchPotato',
|
||||
notifications = ["Updates"],
|
||||
defaultNotifications = ["Updates"],
|
||||
applicationIcon = 'http://couchpota.to/media/images/couch.png',
|
||||
)
|
||||
self.growl.register()
|
||||
def startGrowl():
|
||||
time.sleep(2)
|
||||
try:
|
||||
self.growl = notifier.GrowlNotifier(
|
||||
applicationName = 'CouchPotato',
|
||||
notifications = ["Updates"],
|
||||
defaultNotifications = ["Updates"],
|
||||
applicationIcon = '%s/static/images/couch.png' % fireEvent('app.api_url', single = True),
|
||||
)
|
||||
self.growl.register()
|
||||
except:
|
||||
log.error('Failed register of growl: %s' % traceback.format_exc())
|
||||
thread.start_new_thread(startGrowl, ())
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class Plugin(object):
|
||||
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', self.__class__.__name__)
|
||||
class_name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
|
||||
|
||||
path = 'static/' + class_name + '/'
|
||||
path = '%s/static/%s/' % (Env.setting('api_key'), class_name)
|
||||
addView(path + '<path:filename>', self.showStatic, static = True)
|
||||
|
||||
if add_to_head:
|
||||
@@ -94,8 +94,6 @@ class Plugin(object):
|
||||
# http request
|
||||
def urlopen(self, url, timeout = 10, params = {}, headers = {}, multipart = False, show_error = True):
|
||||
|
||||
socket.setdefaulttimeout(timeout)
|
||||
|
||||
# Fill in some headers
|
||||
if not headers.get('Referer'):
|
||||
headers['Referer'] = urlparse(url).hostname
|
||||
@@ -114,13 +112,13 @@ class Plugin(object):
|
||||
cookies = cookielib.CookieJar()
|
||||
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler)
|
||||
|
||||
data = opener.open(request).read()
|
||||
data = opener.open(request, timeout = timeout).read()
|
||||
else:
|
||||
log.info('Opening url: %s, params: %s' % (url, [x for x in params.iterkeys()]))
|
||||
data = urllib.urlencode(params) if len(params) > 0 else None
|
||||
request = urllib2.Request(url, data, headers)
|
||||
|
||||
data = urllib2.urlopen(request).read()
|
||||
data = urllib2.urlopen(request, timeout = timeout).read()
|
||||
except IOError:
|
||||
if show_error:
|
||||
log.error('Failed opening url in %s: %s %s' % (self.getName(), url, traceback.format_exc(1)))
|
||||
|
||||
@@ -290,11 +290,11 @@ class Renamer(Plugin):
|
||||
|
||||
# Remove files
|
||||
for src in remove_files:
|
||||
log.info('Removing "%s"' % src)
|
||||
log.info('(fake) Removing "%s"' % src)
|
||||
|
||||
# Remove matching releases
|
||||
for release in remove_releases:
|
||||
log.info('Removing release %s' % release)
|
||||
log.info('(fake) Removing release %s' % release)
|
||||
|
||||
# Search for trailers etc
|
||||
fireEventAsync('renamer.after', group)
|
||||
|
||||
@@ -528,7 +528,9 @@ class Scanner(Plugin):
|
||||
return True
|
||||
|
||||
def isSampleFile(self, filename):
|
||||
return re.search('(^|[\W_])sample\d*[\W_]', filename.lower())
|
||||
is_sample = re.search('(^|[\W_])sample\d*[\W_]', filename.lower())
|
||||
if is_sample: log.debug('Is sample file: %s' % filename)
|
||||
return is_sample
|
||||
|
||||
def filesizeBetween(self, file, min = 0, max = 100000):
|
||||
try:
|
||||
|
||||
@@ -16,18 +16,18 @@ log = CPLog(__name__)
|
||||
class Searcher(Plugin):
|
||||
|
||||
def __init__(self):
|
||||
addEvent('searcher.all', self.all)
|
||||
addEvent('searcher.all', self.all_movies)
|
||||
addEvent('searcher.single', self.single)
|
||||
addEvent('searcher.correct_movie', self.correctMovie)
|
||||
addEvent('searcher.download', self.download)
|
||||
|
||||
# Schedule cronjob
|
||||
fireEvent('schedule.cron', 'searcher.all', self.all, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
|
||||
fireEvent('schedule.cron', 'searcher.all', self.all_movies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
|
||||
|
||||
if not Env.setting('development'):
|
||||
addEvent('app.load', self.all)
|
||||
addEvent('app.load', self.all_movies)
|
||||
|
||||
def all(self):
|
||||
def all_movies(self):
|
||||
|
||||
db = get_session()
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import os.path
|
||||
import time
|
||||
|
||||
|
||||
class Settings():
|
||||
class Settings(object):
|
||||
|
||||
options = {}
|
||||
types = {}
|
||||
|
||||
@@ -10,8 +10,8 @@ import locale
|
||||
import logging
|
||||
import os.path
|
||||
import sys
|
||||
import traceback
|
||||
import time
|
||||
import traceback
|
||||
|
||||
def getOptions(base_path, args):
|
||||
|
||||
@@ -180,7 +180,8 @@ def runCouchPotato(options, base_path, args, desktop = None):
|
||||
}
|
||||
|
||||
# Static path
|
||||
web.add_url_rule('static/<path:filename>',
|
||||
app.static_folder = os.path.join(base_path, 'couchpotato', 'static')
|
||||
web.add_url_rule('%s/static/<path:filename>' % api_key,
|
||||
endpoint = 'static',
|
||||
view_func = app.send_static_file)
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
@@ -13,6 +13,7 @@ Page.Wanted = new Class({
|
||||
// Wanted movies
|
||||
self.wanted = new MovieList({
|
||||
'status': 'active',
|
||||
'navigation': true,
|
||||
'actions': MovieActions
|
||||
});
|
||||
$(self.wanted).inject(self.el);
|
||||
|
||||
+65
-65
@@ -6,59 +6,61 @@
|
||||
# http://www.valuedlessons.com/2008/04/events-in-python.html
|
||||
#
|
||||
# This module is part of Axel and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
#
|
||||
# Source: http://pypi.python.org/pypi/axel
|
||||
# Docs: http://packages.python.org/axel
|
||||
|
||||
from couchpotato.core.helpers.variable import natcmp
|
||||
import Queue
|
||||
import hashlib
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
class Event(object):
|
||||
"""
|
||||
"""
|
||||
Event object inspired by C# events. Handlers can be registered and
|
||||
unregistered using += and -= operators. Execution and result are
|
||||
unregistered using += and -= operators. Execution and result are
|
||||
influenced by the arguments passed to the constructor and += method.
|
||||
|
||||
|
||||
from axel import Event
|
||||
|
||||
|
||||
event = Event()
|
||||
def on_event(*args, **kwargs):
|
||||
return (args, kwargs)
|
||||
|
||||
|
||||
event += on_event # handler registration
|
||||
print(event(10, 20, y=30))
|
||||
print(event(10, 20, y=30))
|
||||
>> ((True, ((10, 20), {'y': 30}), <function on_event at 0x00BAA270>),)
|
||||
|
||||
|
||||
event -= on_event # handler is unregistered
|
||||
print(event(10, 20, y=30))
|
||||
print(event(10, 20, y=30))
|
||||
>> None
|
||||
|
||||
|
||||
class Mouse(object):
|
||||
def __init__(self):
|
||||
self.click = Event(self)
|
||||
self.click += self.on_click # handler registration
|
||||
|
||||
|
||||
def on_click(self, sender, *args, **kwargs):
|
||||
assert isinstance(sender, Mouse), 'Wrong sender'
|
||||
return (args, kwargs)
|
||||
|
||||
|
||||
mouse = Mouse()
|
||||
print(mouse.click(10, 20))
|
||||
>> ((True, ((10, 20), {}),
|
||||
print(mouse.click(10, 20))
|
||||
>> ((True, ((10, 20), {}),
|
||||
>> <bound method Mouse.on_click of <__main__.Mouse object at 0x00B6F470>>),)
|
||||
|
||||
|
||||
mouse.click -= mouse.on_click # handler is unregistered
|
||||
print(mouse.click(10, 20))
|
||||
print(mouse.click(10, 20))
|
||||
>> None
|
||||
"""
|
||||
|
||||
def __init__(self, sender = None, asynch = False, exc_info = False,
|
||||
lock = None, threads = 3, traceback = False):
|
||||
""" Creates an event
|
||||
|
||||
""" Creates an event
|
||||
|
||||
asynch
|
||||
if True handler's are executes asynchronous
|
||||
exc_info
|
||||
@@ -66,31 +68,31 @@ class Event(object):
|
||||
lock
|
||||
threading.RLock used to synchronize execution
|
||||
sender
|
||||
event's sender. The sender is passed as the first argument to the
|
||||
event's sender. The sender is passed as the first argument to the
|
||||
handler, only if is not None. For this case the handler must have
|
||||
a placeholder in the arguments to receive the sender
|
||||
threads
|
||||
maximum number of threads that will be started
|
||||
traceback
|
||||
if True, the execution result will contain sys.exc_info()
|
||||
on error. exc_info must be also True to get the traceback
|
||||
|
||||
hash = hash(handler)
|
||||
|
||||
Handlers are stored in a dictionary that has as keys the handler's hash
|
||||
handlers = {
|
||||
if True, the execution result will contain sys.exc_info()
|
||||
on error. exc_info must be also True to get the traceback
|
||||
|
||||
hash = self.hash(handler)
|
||||
|
||||
Handlers are stored in a dictionary that has as keys the handler's hash
|
||||
handlers = {
|
||||
hash : (handler, memoize, timeout),
|
||||
hash : (handler, memoize, timeout), ...
|
||||
hash : (handler, memoize, timeout), ...
|
||||
}
|
||||
The execution result is cached using the following structure
|
||||
memoize = {
|
||||
hash : ((args, kwargs, result), (args, kwargs, result), ...),
|
||||
hash : ((args, kwargs, result), ...), ...
|
||||
}
|
||||
The execution result is cached using the following structure
|
||||
memoize = {
|
||||
hash : ((args, kwargs, result), (args, kwargs, result), ...),
|
||||
hash : ((args, kwargs, result), ...), ...
|
||||
}
|
||||
The execution result is returned as a tuple having this structure
|
||||
exec_result = (
|
||||
(True, result, handler), # on success
|
||||
(False, error_info, handler), # on error
|
||||
(False, error_info, handler), # on error
|
||||
(None, None, handler), ... # asynchronous execution
|
||||
)
|
||||
"""
|
||||
@@ -103,31 +105,34 @@ class Event(object):
|
||||
self.handlers = {}
|
||||
self.memoize = {}
|
||||
|
||||
def hash(self, handler):
|
||||
return hashlib.md5(str(handler)).hexdigest()
|
||||
|
||||
def handle(self, handler, priority = 0):
|
||||
""" Registers a handler. The handler can be transmitted together
|
||||
""" Registers a handler. The handler can be transmitted together
|
||||
with two arguments as a list or dictionary. The arguments are:
|
||||
|
||||
memoize
|
||||
|
||||
memoize
|
||||
if True, the execution result will be cached in self.memoize
|
||||
timeout
|
||||
timeout
|
||||
will allocate a predefined time interval for the execution
|
||||
|
||||
If arguments are provided as a list, they are considered to have
|
||||
this sequence: (handler, memoize, timeout)
|
||||
|
||||
|
||||
If arguments are provided as a list, they are considered to have
|
||||
this sequence: (handler, memoize, timeout)
|
||||
|
||||
Examples:
|
||||
event += handler
|
||||
event += handler
|
||||
event += (handler, True, 1.5)
|
||||
event += {'handler':handler, 'memoize':True, 'timeout':1.5}
|
||||
event += {'handler':handler, 'memoize':True, 'timeout':1.5}
|
||||
"""
|
||||
handler_, memoize, timeout = self._extract(handler)
|
||||
self.handlers['%s.%s' % (priority, hash(handler_))] = (handler_, memoize, timeout)
|
||||
self.handlers['%s.%s' % (priority, self.hash(handler_))] = (handler_, memoize, timeout)
|
||||
return self
|
||||
|
||||
def unhandle(self, handler):
|
||||
""" Unregisters a handler """
|
||||
handler_, memoize, timeout = self._extract(handler)
|
||||
key = hash(handler_)
|
||||
key = self.hash(handler_)
|
||||
if not key in self.handlers:
|
||||
raise ValueError('Handler "%s" was not found' % str(handler_))
|
||||
del self.handlers[key]
|
||||
@@ -139,6 +144,7 @@ class Event(object):
|
||||
self.result = []
|
||||
|
||||
if self.handlers:
|
||||
|
||||
max_threads = self._threads()
|
||||
|
||||
for i in range(max_threads):
|
||||
@@ -172,10 +178,8 @@ class Event(object):
|
||||
""" Executes all handlers stored in the queue """
|
||||
while True:
|
||||
try:
|
||||
handler, memoize, timeout = self.handlers[self.queue.get()]
|
||||
|
||||
if isinstance(self.lock, threading._RLock):
|
||||
self.lock.acquire() #synchronization
|
||||
h_ = self.queue.get()
|
||||
handler, memoize, timeout = self.handlers[h_]
|
||||
|
||||
try:
|
||||
r = self._memoize(memoize, timeout, handler, *args, **kwargs)
|
||||
@@ -189,14 +193,9 @@ class Event(object):
|
||||
else:
|
||||
self.error_handler(sys.exc_info())
|
||||
finally:
|
||||
if isinstance(self.lock, threading._RLock):
|
||||
self.lock.release()
|
||||
|
||||
if not self.asynchronous:
|
||||
try:
|
||||
self.queue.task_done()
|
||||
except ValueError:
|
||||
pass
|
||||
self.queue.task_done()
|
||||
|
||||
if self.queue.empty():
|
||||
raise Queue.Empty
|
||||
@@ -205,9 +204,9 @@ class Event(object):
|
||||
break
|
||||
|
||||
def _extract(self, queue_item):
|
||||
""" Extracts a handler and handler's arguments that can be provided
|
||||
as list or dictionary. If arguments are provided as list, they are
|
||||
considered to have this sequence: (handler, memoize, timeout)
|
||||
""" Extracts a handler and handler's arguments that can be provided
|
||||
as list or dictionary. If arguments are provided as list, they are
|
||||
considered to have this sequence: (handler, memoize, timeout)
|
||||
Examples:
|
||||
event += handler
|
||||
event += (handler, True, 1.5)
|
||||
@@ -234,11 +233,11 @@ class Event(object):
|
||||
return (handler, bool(memoize), float(timeout))
|
||||
|
||||
def _memoize(self, memoize, timeout, handler, *args, **kwargs):
|
||||
""" Caches the execution result of successful executions
|
||||
hash = hash(handler)
|
||||
memoize = {
|
||||
hash : ((args, kwargs, result), (args, kwargs, result), ...),
|
||||
hash : ((args, kwargs, result), ...), ...
|
||||
""" Caches the execution result of successful executions
|
||||
hash = self.hash(handler)
|
||||
memoize = {
|
||||
hash : ((args, kwargs, result), (args, kwargs, result), ...),
|
||||
hash : ((args, kwargs, result), ...), ...
|
||||
}
|
||||
"""
|
||||
if not isinstance(handler, Event) and self.sender is not None:
|
||||
@@ -247,7 +246,8 @@ class Event(object):
|
||||
|
||||
if not memoize:
|
||||
if timeout <= 0: #no time restriction
|
||||
return [True, handler(*args, **kwargs), handler]
|
||||
result = [True, handler(*args, **kwargs), handler]
|
||||
return result
|
||||
|
||||
result = self._timeout(timeout, handler, *args, **kwargs)
|
||||
if isinstance(result, tuple) and len(result) == 3:
|
||||
@@ -255,7 +255,7 @@ class Event(object):
|
||||
return [False, self._error(result), handler]
|
||||
return [True, result, handler]
|
||||
else:
|
||||
hash_ = hash(handler)
|
||||
hash_ = self.hash(handler)
|
||||
if hash_ in self.memoize:
|
||||
for args_, kwargs_, result in self.memoize[hash_]:
|
||||
if args_ == args and kwargs_ == kwargs:
|
||||
|
||||
Reference in New Issue
Block a user