pypkjs 1.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pypkjs/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ from gevent import monkey
5
+ monkey.patch_all()
@@ -0,0 +1,40 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ from .console import Console
5
+ from .performance import Performance
6
+ from .timers import Timers
7
+ from .localstorage import LocalStorage
8
+ from .pebble import Pebble
9
+ from .xhr import prepare_xhr
10
+ from .navigator import Navigator
11
+ from .ws import prepare_ws
12
+
13
+
14
+ class PebbleKitJS(object):
15
+ def __init__(self, runtime, pebble, persist=None):
16
+ self.runtime = runtime
17
+ self.pebble = Pebble(runtime, pebble)
18
+ self.local_storage = LocalStorage(runtime, persist)
19
+
20
+ self.extensions = [
21
+ Console(runtime),
22
+ Performance(runtime),
23
+ self.local_storage,
24
+ Navigator(runtime),
25
+ Timers(runtime),
26
+ self.pebble,
27
+ ]
28
+
29
+ def get_extension_names(self):
30
+ return [x.extension.name for x in self.extensions] + ["runtime/events/progress", "runtime/xhr", "runtime/ws",
31
+ "runtime/geolocation/position",
32
+ "runtime/geolocation/coordinates"]
33
+
34
+ def do_post_setup(self):
35
+ prepare_xhr(self.runtime)
36
+ prepare_ws(self.runtime)
37
+
38
+ def shutdown(self):
39
+ self.local_storage._shutdown()
40
+ self.pebble._shutdown()
@@ -0,0 +1,39 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ import STPyV8 as v8
5
+
6
+
7
+ class Console(object):
8
+ def __init__(self, runtime):
9
+ self.runtime = runtime
10
+ self.extension = v8.JSExtension(self.runtime.ext_name("console"), """
11
+ console = new (function () {
12
+ native function _internal_console();
13
+ _make_proxies(this, _internal_console(), ['log', 'warn', 'info', 'error']);
14
+ })();
15
+ """, lambda f: lambda: self, dependencies=["runtime/internal/proxy"])
16
+
17
+ def log(self, *params):
18
+ # kOverview == kLineNumber | kColumnOffset | kScriptName | kFunctionName
19
+ trace_str = str(v8.JSStackTrace.GetCurrentStackTrace(2, v8.JSStackTrace.Options.Overview))
20
+ try:
21
+ frames = v8.JSError.parse_stack(trace_str.strip())
22
+ caller_frame = frames[0]
23
+ filename = caller_frame[1]
24
+ line_num = caller_frame[2]
25
+ file_and_line = "{}:{}".format(filename, line_num)
26
+ except:
27
+ file_and_line = "???:?:?"
28
+ log_str = ' '.join([x.toString().decode('utf-8') if hasattr(x, 'toString')
29
+ else bytes(x).decode('utf-8') for x in params])
30
+ self.runtime.log_output("{} {}".format(file_and_line, log_str))
31
+
32
+ def warn(self, *params):
33
+ self.log(*params)
34
+
35
+ def info(self, *params):
36
+ self.log(*params)
37
+
38
+ def error(self, *params):
39
+ self.log(*params)
@@ -0,0 +1,91 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ import STPyV8 as v8
5
+
6
+ from .exceptions import JSRuntimeException
7
+
8
+ event = v8.JSExtension("runtime/event", """
9
+ Event = function(event_type, event_init_dict) {
10
+ var self = this;
11
+ this.stopPropagation = function() {};
12
+ this.stopImmediatePropagation = function() { self._aborted = true; }
13
+ this.preventDefault = function() { self.defaultPrevented = true; }
14
+ this.initEvent = function(event_type, bubbles, cancelable) {
15
+ self.type = event_type;
16
+ self.bubbles = bubbles;
17
+ self.cancelable = cancelable
18
+ };
19
+ if(!event_init_dict) event_init_dict = {};
20
+
21
+ this.type = event_type;
22
+ this.bubbles = event_init_dict.bubbles || false;
23
+ this.cancelable = event_init_dict.cancelable || false;
24
+ this.defaultPrevented = false;
25
+ this.target = null;
26
+ this.currentTarget = null;
27
+ this.eventPhase = 2;
28
+ this._aborted = false;
29
+ };
30
+ Event.NONE = 0;
31
+ Event.CAPTURING_PHASE = 1;
32
+ Event.AT_TARGET = 2;
33
+ Event.BUBBLING_PHASE = 3;
34
+ """)
35
+
36
+ Event = lambda runtime, *args: v8.JSObject.create(runtime.context.locals.Event, args)
37
+
38
+
39
+ class EventSourceMixin(object):
40
+ def __init__(self, runtime):
41
+ self.__listeners = {}
42
+ self.__runtime = runtime
43
+ super(EventSourceMixin, self).__init__()
44
+
45
+ def addEventListener(self, event, listener, capture=False):
46
+ self.__listeners.setdefault(event, []).append(listener)
47
+
48
+ def removeEventListener(self, event, listener=None):
49
+ if event not in self.__listeners:
50
+ return
51
+ if listener is None:
52
+ del self.__listeners[event]
53
+ else:
54
+ for i, listener_i in enumerate(self.__listeners[event]):
55
+ if listener_i == listener:
56
+ del listener[i]
57
+ break
58
+
59
+ def triggerEvent(self, event_name, event=None, *params):
60
+ if event is None:
61
+ event = Event(self.__runtime, event_name)
62
+
63
+ def go():
64
+ for listener in self.__listeners.get(event_name, []):
65
+ try:
66
+ listener.call(self, event, *params)
67
+ except (v8.JSError, JSRuntimeException) as e:
68
+ self.__runtime.log_output(e.stackTrace)
69
+ except Exception as e:
70
+ self.__runtime.log_output(e.message)
71
+ raise
72
+ finally:
73
+ if event._aborted:
74
+ break
75
+ #TODO: Figure out if these come before or after addEventListener handlers.
76
+ try:
77
+ dom_event = getattr(self, "on" + event_name)
78
+ except AttributeError:
79
+ pass
80
+ else:
81
+ try:
82
+ if dom_event is not None:
83
+ dom_event.call(self, event, *params)
84
+ except (v8.JSError, JSRuntimeException) as e:
85
+ self.__runtime.log_output(e.stackTrace)
86
+ except Exception as e:
87
+ self.__runtime.log_output(e.message)
88
+ raise
89
+
90
+ self.__runtime.enqueue(go)
91
+
@@ -0,0 +1,11 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ import STPyV8 as v8
5
+
6
+
7
+ class JSRuntimeException(Exception):
8
+ def __init__(self, message):
9
+ trace = v8.JSStackTrace.GetCurrentStackTrace(20, v8.JSStackTrace.Options.Detailed)
10
+ self.stackTrace = "Error: %s\n%s" % (message, str(trace))
11
+ Exception.__init__(self, message)
@@ -0,0 +1,88 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ import STPyV8 as v8
5
+ import errno
6
+ import logging
7
+ import os
8
+ import os.path
9
+ import dbm.dumb # This is the only one that actually syncs data if the process dies before I can close().
10
+ logger = logging.getLogger("pypkjs.javascript.localstorage")
11
+
12
+ _storage_cache = {} # This is used when filesystem-based storage is unavailable.
13
+
14
+
15
+ class LocalStorage(object):
16
+ def __init__(self, runtime, persist_dir=None):
17
+ self.storage = None
18
+ if persist_dir is not None:
19
+ try:
20
+ try:
21
+ os.makedirs(os.path.join(persist_dir, 'localstorage'))
22
+ except OSError as e:
23
+ if e.errno != errno.EEXIST:
24
+ raise
25
+
26
+ self.storage = dbm.dumb.open(os.path.join(persist_dir, 'localstorage', str(runtime.pbw.uuid)), 'c')
27
+ except IOError:
28
+ pass
29
+ if self.storage is None:
30
+ logger.warning("Using transient store.")
31
+ self.storage = _storage_cache.setdefault(str(runtime.pbw.uuid), {})
32
+
33
+ self.extension = v8.JSExtension(runtime.ext_name("localstorage"), """
34
+ (function() {
35
+ native function _internal();
36
+
37
+ var proxy = _make_proxies({}, _internal(), ['set', 'has', 'delete_', 'keys', 'enumerate']);
38
+ var methods = _make_proxies({}, _internal(), ['clear', 'getItem', 'setItem', 'removeItem', 'key']);
39
+ proxy.get = function get(p, name) { return methods[name] || _internal().get(p, name); }
40
+
41
+ this.localStorage = Proxy.create(proxy);
42
+ })();
43
+ """, lambda f: lambda: self, dependencies=["runtime/internal/proxy"])
44
+
45
+ def get(self, p, name):
46
+ return self.storage.get(str(name), v8.JSNull())
47
+
48
+ def set(self, p, name, value):
49
+ self.storage[str(name)] = str(value)
50
+ return True
51
+
52
+ def has(self, p, name):
53
+ return name in self.storage
54
+
55
+ def delete_(self, p, name):
56
+ if name in self.storage:
57
+ del self.storage[name]
58
+ return True
59
+ else:
60
+ return False
61
+
62
+ def keys(self, p):
63
+ return v8.JSArray(list(self.storage.keys()))
64
+
65
+ def enumerate(self):
66
+ return v8.JSArray(list(self.storage.keys()))
67
+
68
+ def clear(self, *args):
69
+ self.storage.clear()
70
+
71
+ def getItem(self, name, *args):
72
+ return self.get(None, name)
73
+
74
+ def setItem(self, name, value, *args):
75
+ self.set(None, name, value)
76
+
77
+ def removeItem(self, name, *args):
78
+ return self.delete_(None, name)
79
+
80
+ def key(self, index, *args):
81
+ if len(self.storage) > index:
82
+ return list(self.storage.keys())[index]
83
+ else:
84
+ return v8.JSNull()
85
+
86
+ def _shutdown(self):
87
+ if hasattr(self.storage, 'close'):
88
+ self.storage.close()
@@ -0,0 +1,27 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ import STPyV8 as v8
5
+ from .geolocation import Geolocation
6
+
7
+
8
+ class Navigator(object):
9
+ def __init__(self, runtime):
10
+
11
+ self._runtime = runtime
12
+ self._runtime = runtime
13
+
14
+ self.extension = v8.JSExtension(runtime.ext_name("navigator"), """
15
+ navigator = new (function() {
16
+ native function _internal_location();
17
+ this.language = 'en-GB';
18
+
19
+ var location = _internal_location();
20
+ if(true) { // TODO: this should be a check on geolocation being enabled.
21
+ this.geolocation = new (function() {
22
+ _make_proxies(this, location, ['getCurrentPosition', 'watchPosition', 'clearWatch']);
23
+ })();
24
+ }
25
+ })();
26
+ """, lambda f: lambda: Geolocation(runtime), dependencies=["runtime/internal/proxy"])
27
+
@@ -0,0 +1,61 @@
1
+
2
+ __author__ = 'katharine'
3
+
4
+ import STPyV8 as v8
5
+ import time
6
+ import requests
7
+ import pygeoip
8
+ import os.path
9
+
10
+ position = v8.JSExtension("runtime/geolocation/position", """
11
+ Position = (function(coords, timestamp) {
12
+ this.coords = coords;
13
+ this.timestamp = timestamp;
14
+ });
15
+ """)
16
+
17
+ Position = lambda runtime, *args: v8.JSObject.create(runtime.context.locals.Position, args)
18
+
19
+ coordinates = v8.JSExtension("runtime/geolocation/coordinates", """
20
+ Coordinates = (function(long, lat, accuracy) {
21
+ this.longitude = long
22
+ this.latitude = lat
23
+ this.accuracy = accuracy
24
+ });
25
+ """)
26
+
27
+ Coordinates = lambda runtime, *args: v8.JSObject.create(runtime.context.locals.Coordinates, args)
28
+
29
+
30
+ class Geolocation(object):
31
+ def __init__(self, runtime):
32
+ self.runtime = runtime
33
+
34
+ def _get_position(self, success, failure):
35
+ try:
36
+ resp = requests.get('http://ip.42.pl/raw')
37
+ resp.raise_for_status()
38
+ ip = resp.text
39
+ gi = pygeoip.GeoIP('%s/GeoLiteCity.dat' % os.path.dirname(__file__))
40
+ record = gi.record_by_addr(ip)
41
+ if record is None:
42
+ if callable(failure):
43
+ self.runtime.enqueue(failure)
44
+ except (requests.RequestException, pygeoip.GeoIPError):
45
+ if callable(failure):
46
+ self.runtime.enqueue(failure)
47
+ else:
48
+ self.runtime.enqueue(success, Position(self.runtime, Coordinates(self.runtime, record['longitude'], record['latitude'], 1000), round(time.time() * 1000)))
49
+
50
+ def _enabled(self):
51
+ return True
52
+
53
+ def getCurrentPosition(self, success, failure=None, options=None):
54
+ self.runtime.group.spawn(self._get_position, success, failure)
55
+
56
+ def watchPosition(self, success, failure=None, options=None):
57
+ self.runtime.group.spawn(self._get_position, success, failure)
58
+ return 42
59
+
60
+ def clearWatch(self, thing):
61
+ pass