186 lines
6.4 KiB
Python
186 lines
6.4 KiB
Python
# coding=utf-8
|
|
|
|
import datetime
|
|
import operator
|
|
|
|
from support.config import config
|
|
from support.helpers import timestamp
|
|
|
|
|
|
def enable_channel_wrapper(func, enforce_route=False):
|
|
"""
|
|
returns the original wrapper :func: (route or handler) if applicable, else the plain to-be-wrapped function
|
|
:param func: original wrapper
|
|
:return: original wrapper or wrapped function
|
|
"""
|
|
def noop(*args, **kwargs):
|
|
def inner(*a, **k):
|
|
"""
|
|
:param a: args
|
|
:param k: kwargs
|
|
:return: originally to-be-wrapped function
|
|
"""
|
|
return a[0] if len(a) else a
|
|
|
|
return inner
|
|
|
|
def wrap(*args, **kwargs):
|
|
return (func if (config.enable_channel or enforce_route) else noop)(*args, **kwargs)
|
|
|
|
return wrap
|
|
|
|
|
|
ROUTE_REGISTRY = {}
|
|
|
|
|
|
def get_func_name(args):
|
|
return list(args).pop(0).__name__
|
|
|
|
|
|
def get_lookup_key(f, args, kwargs):
|
|
return tuple([f.__name__, tuple(args), tuple([(key, value) for key, value in kwargs.iteritems()])])
|
|
|
|
|
|
def should_debounce(f, key, kw):
|
|
return getattr(f, "debounce", False) and "randomize" in kw and key in Dict["menu_history"]
|
|
|
|
|
|
def register_route_function(f):
|
|
fn = f.__name__
|
|
if fn != "ValidatePrefs" and fn not in ROUTE_REGISTRY:
|
|
ROUTE_REGISTRY[fn] = f
|
|
return f
|
|
|
|
|
|
def main_menu_fallback():
|
|
key = get_lookup_key(ROUTE_REGISTRY["fatality"], [], {})
|
|
Dict["last_menu_item"] = key
|
|
add_to_menu_history(key)
|
|
|
|
return ROUTE_REGISTRY["fatality"](randomize=timestamp())
|
|
|
|
|
|
def add_to_menu_history(key):
|
|
# add function to menu history
|
|
mh = Dict["menu_history"]
|
|
if key in mh:
|
|
del mh[key]
|
|
|
|
mh[key] = datetime.datetime.now() + datetime.timedelta(hours=6)
|
|
|
|
# limit to 25 items
|
|
Dict["menu_history"] = dict(sorted(sorted(mh.items(), key=operator.itemgetter(1),
|
|
reverse=True)[:25]))
|
|
|
|
try:
|
|
Dict.Save()
|
|
except TypeError:
|
|
Log.Error("Can't save menu history for: %r", key)
|
|
del Dict["menu_history"][key]
|
|
|
|
|
|
def route_wrapper(*args, **kwargs):
|
|
def wrap(f):
|
|
already_wrapped = getattr(f, "orig_f", False)
|
|
|
|
register_route_function(f)
|
|
|
|
def inner(*a, **kw):
|
|
if "menu_history" not in Dict:
|
|
Dict["menu_history"] = {}
|
|
|
|
if "last_menu_item" not in Dict:
|
|
Dict["last_menu_item"] = None
|
|
|
|
key = get_lookup_key(f, list(a), kw)
|
|
|
|
ret_f = f
|
|
ret_a = a
|
|
ret_kw = kw
|
|
# mh = Dict["menu_history"]
|
|
# mh_keys = [k for k, v in sorted(mh.items(), key=operator.itemgetter(1))]
|
|
#
|
|
# fallback_needed = False
|
|
# fallback_found = False
|
|
|
|
if should_debounce(ret_f, key, kw):
|
|
# special case for TriggerRestart
|
|
if ret_f.__name__ in ("TriggerRestart", "Restart"):
|
|
Log.Debug("Don't trigger a re-restart, falling back to main menu")
|
|
else:
|
|
Log.Debug("not triggering %s twice with %s, %s, returning to main menu" %
|
|
(f.__name__, a, kw))
|
|
|
|
return main_menu_fallback()
|
|
#
|
|
# fallback_needed = True
|
|
#
|
|
# # try to find a suitable fallback route in case we've encountered an already visited
|
|
# # debounced route
|
|
# fallbacks = []
|
|
# current_last_visit = mh[key]
|
|
# last_menu_item = Dict["last_menu_item"]
|
|
# direction_backwards = True
|
|
#
|
|
# if last_menu_item and last_menu_item in mh and key in mh:
|
|
# last_mi_pos = mh_keys.index(last_menu_item)
|
|
# current_mi_pos = mh_keys.index(key)
|
|
# if current_mi_pos > -1 and last_mi_pos > -1:
|
|
# print "SHEKEL", current_mi_pos, last_mi_pos, current_mi_pos < last_mi_pos
|
|
|
|
# only consider items in menu history that have an older timestamp than the current
|
|
# for key_, last_visit in sorted(mh.items(), key=operator.itemgetter(1),
|
|
# reverse=True):
|
|
# if last_visit < current_last_visit:
|
|
# fallbacks.append(key_)
|
|
#
|
|
# for key_ in fallbacks:
|
|
# # old data structure
|
|
# if not len(key_) == 3 or not (isinstance(key_[1], tuple) and isinstance(key_[2], tuple)):
|
|
# continue
|
|
#
|
|
# old_f, old_a, old_kw = key_
|
|
# if old_f == "ValidatePrefs":
|
|
# continue
|
|
#
|
|
# possible_fallback = ROUTE_REGISTRY[old_f]
|
|
#
|
|
# # non-debounced function found
|
|
# if not getattr(possible_fallback, "debounce", False):
|
|
# ret_kw = dict(old_kw)
|
|
# ret_a = old_a
|
|
# if "randomize" in ret_kw:
|
|
# ret_kw["randomize"] = timestamp()
|
|
#
|
|
# ret_f = possible_fallback
|
|
# key = get_lookup_key(ret_f, list(ret_a), ret_kw)
|
|
# fallback_found = True
|
|
#
|
|
# Log.Debug("not triggering %s twice with %s, %s, returning to %s, %s, %s" %
|
|
# (f.__name__, a, kw, ret_f.__name__, ret_a, ret_kw))
|
|
#
|
|
# break
|
|
#
|
|
# if not fallback_found:
|
|
# Log.Debug("No fallback found in menu history for %s, falling back to main menu", f)
|
|
# return main_menu_fallback()
|
|
|
|
# if not fallback_needed:
|
|
# add_to_menu_history(key)
|
|
# if ret_f.__name__ != "ValidatePrefs":
|
|
# Dict["last_menu_item"] = key
|
|
#
|
|
add_to_menu_history(key)
|
|
Dict["last_menu_item"] = key
|
|
return ret_f(*ret_a, **ret_kw)
|
|
|
|
# @route may be used multiple times
|
|
enforce_route = kwargs.pop("enforce_route", None)
|
|
if not already_wrapped:
|
|
inner.orig_f = f
|
|
|
|
return enable_channel_wrapper(route(*args, **kwargs), enforce_route=enforce_route)(inner)
|
|
return enable_channel_wrapper(route(*args, **kwargs), enforce_route=enforce_route)(f)
|
|
|
|
return wrap
|