diff --git a/config.json b/config.json index c61c0be..a74884f 100644 --- a/config.json +++ b/config.json @@ -110,7 +110,8 @@ "title": "Extension", "type": "string", "columnWidth": 80, - "sort": true + "sort": true, + "find": true }, { "id": "size", @@ -319,6 +320,7 @@ "username": "" }, "ui": { + "coverSize": 256, "fileInfo": "extension", "filters": [ {"id": "author", "sort": [{"key": "items", "operator": "-"}]}, diff --git a/ctl b/ctl index aaa7db5..bfb04be 100755 --- a/ctl +++ b/ctl @@ -90,8 +90,8 @@ if [ "$1" == "update" ]; then cd $BASE/$NAME git pull find . -name '*.pyc' -exec rm "{}" \; - $0 setup - $0 update_static > /dev/null + python2 oml setup + python2 oml update_static > /dev/null exit fi diff --git a/oml/changelog.py b/oml/changelog.py index f2df8e6..85c0411 100644 --- a/oml/changelog.py +++ b/oml/changelog.py @@ -151,7 +151,8 @@ class Changelog(db.Model): if not i: i = Item.get_or_create(itemid, info) i.modified = datetime.fromtimestamp(float(timestamp)) - i.users.append(user) + if user not in i.users: + i.users.append(user) i.update() return True diff --git a/oml/node/nodeapi.py b/oml/node/nodeapi.py index 9cd70d7..5f734d5 100644 --- a/oml/node/nodeapi.py +++ b/oml/node/nodeapi.py @@ -70,7 +70,6 @@ def api_acceptPeering(app, user_id, username, message): user.info['username'] = username user.info['message'] = message user.update_peering(True, username) - trigger_event('peering.accept', user.json()) state.nodes.queue('add', user.id) return True return False diff --git a/oml/nodes.py b/oml/nodes.py index cf1b086..dea4946 100644 --- a/oml/nodes.py +++ b/oml/nodes.py @@ -11,6 +11,7 @@ import gzip import urllib2 from datetime import datetime import os +import time import ox import ed25519 @@ -30,7 +31,8 @@ logger = logging.getLogger('oml.nodes') ENCODING='base64' -class Node(object): +class Node(Thread): + _running = True _cert = None online = False download_speed = 0 @@ -42,10 +44,36 @@ class Node(object): self.user_id = user.id key = str(user.id) self.vk = ed25519.VerifyingKey(key, encoding=ENCODING) - self.go_online() logger.debug('new Node %s online=%s', self.user_id, self.online) + self._q = Queue() + Thread.__init__(self) + self.daemon = True + self.start() self._ping = PeriodicCallback(self.ping, 120000) self._ping.start() + self.ping() + + def run(self): + with self._app.app_context(): + while self._running: + action = self._q.get() + if not self._running: + break + if action == 'go_online' or not self.online: + self._go_online() + else: + self.online = self.can_connect() + + def join(self): + self._running = False + self.ping() + return Thread.join(self) + + def ping(self): + self._q.put('') + + def go_online(self): + self._q.put('go_online') @property def url(self): @@ -148,30 +176,26 @@ class Node(object): def can_connect(self): try: - s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) - s.settimeout(1) - s.connect((self.host, self.port)) - s.close() + logger.debug('try to connect to %s', self.url) + r = self._opener.open(self.url, timeout=1) + c = r.read() + logger.debug('ok') return True except: pass + logger.debug('failed') return False - def ping(self): - with self._app.app_context(): - if self.online: - self.online = self.can_connect() - else: - self.go_online() - - def go_online(self): + def _go_online(self): self.resolve() u = self.user + logger.debug('go_online peer=%s queued=%s (%s)', u.peered, u.queued, u.id) if u.peered or u.queued: try: self.online = False - logger.debug('type to connect to %s at [%s]:%s', self.user_id, self.host, self.port) + logger.debug('try to connect to %s at [%s]:%s', self.user_id, self.host, self.port) if self.can_connect(): + logger.debug('connected to [%s]:%s', self.host, self.port) self.online = True if u.queued: logger.debug('queued peering event pending=%s peered=%s', u.pending, u.peered) @@ -184,12 +208,14 @@ class Node(object): self.peering('removePeering') if self.online: self.pullChanges() - logger.debug('connected to %s', self.user_id) except: logger.debug('failed to connect to %s', self.user_id, exc_info=1) self.online = False else: self.online = False + self.trigger_status() + + def trigger_status(self): trigger_event('status', { 'id': self.user_id, 'online': self.online @@ -210,10 +236,7 @@ class Node(object): r = self.request('pushChanges', changes) except: self.online = False - trigger_event('status', { - 'id': self.user_id, - 'online': self.online - }) + self.trigger_status() r = False logger.debug('pushedChanges %s %s', r, self.user_id) @@ -230,9 +253,11 @@ class Node(object): u.save() else: logger.debug('peering failed? %s %s', action, r) - if action in ('cancelPeering', 'rejectPeering', 'removePeering'): self.online = False + else: + self.go_online() + trigger_event('peering.%s'%action.replace('Peering', ''), u.json()) return True def download(self, item): @@ -336,7 +361,7 @@ class Nodes(Thread): self._nodes[user_id] = Node(self, User.get_or_create(user_id)) else: if not self._nodes[user_id].online: - self._nodes[user_id].go_online() + self._nodes[user_id].ping() def run(self): with self._app.app_context(): @@ -351,4 +376,6 @@ class Nodes(Thread): def join(self): self._running = False self._q.put(None) + for node in self._nodes.values(): + node.join() return Thread.join(self) diff --git a/oml/ssl_request.py b/oml/ssl_request.py index d996fb0..1ce8fcf 100644 --- a/oml/ssl_request.py +++ b/oml/ssl_request.py @@ -42,7 +42,7 @@ class CertValidatingHTTPSConnection(httplib.HTTPConnection): if not self._ValidateCertificateFingerprint(cert): raise InvalidCertificateException(self.fingerprint, cert, 'fingerprint mismatch') - logger.debug('CIPHER %s VERSION %s', self.sock.cipher(), self.sock.ssl_version) + #logger.debug('CIPHER %s VERSION %s', self.sock.cipher(), self.sock.ssl_version) class VerifiedHTTPSHandler(urllib2.HTTPSHandler): def __init__(self, **kwargs): diff --git a/oml/user/models.py b/oml/user/models.py index 032e1a8..36d3bbc 100644 --- a/oml/user/models.py +++ b/oml/user/models.py @@ -76,7 +76,6 @@ class User(db.Model): def update_peering(self, peered, username=None): was_peering = self.peered - self.queued = True if peered: self.pending = '' if username: @@ -90,6 +89,7 @@ class User(db.Model): if not was_peering: Changelog.record(state.user(), 'addpeer', self.id, self.nickname) self.peered = True + self.queued = True self.save() else: self.pending = '' diff --git a/static/js/findElement.js b/static/js/findElement.js index 24353ba..8c4b2da 100644 --- a/static/js/findElement.js +++ b/static/js/findElement.js @@ -86,18 +86,19 @@ oml.ui.findElement = function() { } }, submit: function(data) { - var scope = oml.$ui.findInSelect.value(), + // FIXME: oml.$ui.findInSelect.value() is undefined + var scope = oml.$ui.findInSelect.options('value'), key = oml.$ui.findSelect.value(), conditions = [].concat( scope == 'list' ? [{ key: 'list', - value: ui._list, - operator: '==' + operator: '==', + value: ui._list }] : [], scope == 'user' ? [{ key: 'list', - value: ui._list.split(':')[0], - operator: '==' + operator: '==', + value: ui._list.split(':')[0] + ':' }] : [], data.value ? [{ key: key, @@ -158,22 +159,29 @@ oml.ui.findElement = function() { } function renderFindInSelect() { - var scope = !ui._list ? 'all' - : Ox.endsWith(ui._list, ':') ? 'user' - : 'list'; - var $select = Ox.Select({ + var items = [ + {id: 'all', title: Ox._('Find In: All Libraries')}, + {id: 'user', title: Ox._('Find In: This Library')}, + {id: 'list', title: Ox._('Find In: This List')} + ], + scope = !ui._list ? 'all' + : Ox.endsWith(ui._list, ':') ? 'user' + : 'list', + $select = Ox.Select({ items: [ - {id: 'all', title: Ox._('Find In: All Libraries')}, + items[0], ].concat(scope != 'all' ? [ - {id: 'user', title: Ox._('Find In: This Library')}, + items[1], ] : []).concat(scope == 'list' ? [ - {id: 'list', title: Ox._('Find In: This List')} + items[2] ] : []), + max: 1, + min: 1, overlap: 'right', style: 'squared', title: scope == 'all' ? 'data' : scope, type: 'image', - tooltip: Ox._('Find: FIXME'), + tooltip: Ox.getObjectById(items, scope).title, value: scope }) .bindEvent({ diff --git a/static/js/folders.js b/static/js/folders.js index 499ec5c..c9cc6e1 100644 --- a/static/js/folders.js +++ b/static/js/folders.js @@ -16,7 +16,10 @@ oml.ui.folders = function() { //overflowY: 'auto', }) .bindEvent({ - oml_find: selectList + oml_find: selectList, + oml_showfolder: function() { + oml.resizeListFolders(); + } }); function getFind(list) { @@ -120,7 +123,7 @@ oml.ui.folders = function() { userIndex[user.nickname] = index; oml.$ui.folder[index] = Ox.CollapsePanel({ - collapsed: false, + collapsed: !ui.showFolder[user.nickname], extras: [ oml.ui.statusIcon(user, index), {}, @@ -263,6 +266,7 @@ oml.ui.folders = function() { }); + oml.resizeListFolders(); // FIXME: DOESN'T WORK selectList(); }); @@ -272,7 +276,6 @@ oml.ui.folders = function() { }; that.updateItems = function(items) { - Ox.print('UPDATE ITEMS', items); var $list; if (arguments.length == 0) { oml.getLists(function(lists) { @@ -306,6 +309,7 @@ oml.ui.folders = function() { }) .css({height: items.length * 16 + 'px'}) .size(); + oml.resizeFolders(); callback && callback(); }); }; @@ -316,10 +320,17 @@ oml.ui.folders = function() { that.updateItems(); } }, + change: function(data) { + Ox.print('got change event') + }, 'peering.accept': function(data) { + Ox.print('peering.accept reload list') + Ox.Request.clearCache('getUsers'); that.updateElement(); }, 'peering.remove': function(data) { + Ox.print('peering.remove reload list') + Ox.Request.clearCache('getUsers'); that.updateElement(); } }); diff --git a/static/js/infoView.js b/static/js/infoView.js index 3261d57..40286a5 100644 --- a/static/js/infoView.js +++ b/static/js/infoView.js @@ -4,6 +4,8 @@ oml.ui.infoView = function(identifyData) { var ui = oml.user.ui, + css = getCSS(ui.coverSize), + that = Ox.Element() .addClass('OxTextPage') .css({overflowY: 'auto'}) @@ -25,7 +27,7 @@ oml.ui.infoView = function(identifyData) { position: 'absolute', left: '16px', top: '16px', - width: '256px' + width: css.cover.width }) .appendTo(that), @@ -33,7 +35,7 @@ oml.ui.infoView = function(identifyData) { .addClass('OxSelectable') .css({ position: 'absolute', - left: '288px', + left: css.info.left, right: !identifyData ? '176px' : 16 + Ox.UI.SCROLLBAR_SIZE + 'px', top: '16px' }) @@ -55,6 +57,28 @@ oml.ui.infoView = function(identifyData) { .appendTo(that); } + function getCSS(size, ratio) { + var width = Math.round(ratio >= 1 ? size : size * ratio), + height = Math.round(ratio <= 1 ? size : size / ratio), + left = size == 256 ? Math.floor((size - width) / 2) : 0; + return { + cover: { + width: size + 'px' + }, + info: { + left: (size == 256 ? size + 32 : width + 48) + 'px' + }, + image: { + left: left + 'px', + width: width + 'px', + height: height + 'px' + }, + reflection: { + top: height + 'px' + } + }; + } + function getImageSize(size, ratio) { var width = Math.round(ratio >= 1 ? size : size * ratio), height = Math.round(ratio <= 1 ? size : size / ratio), @@ -82,19 +106,6 @@ oml.ui.infoView = function(identifyData) { function identify(data) { oml.ui.identifyDialog(data).open(); - return; - $identifyPanel.select('id'); - $identifyDialog.open(); - identify(data); - function identify(data) { - oml.api.identify(data, function(result) { - $identifyList.options({ - items: result.data.items.map(function(item, index) { - return Ox.extend(item, {index: index}); - }) - }); - }); - } } function renderMediaButton(data) { @@ -213,23 +224,29 @@ oml.ui.infoView = function(identifyData) { return $element; } - function updateCover(size, ratio) { - var width = Math.round(ratio >= 1 ? size : size * ratio), - height = Math.round(ratio <= 1 ? size : size / ratio), - left = Math.floor((size - width) / 2); - $image.css({ - left: left + 'px', - width: width + 'px', - height: height + 'px' - }).show(); - $reflectionImage.css({ - left: left + 'px', - width: width + 'px', - height: height + 'px' - }); - $reflection.css({ - top: height + 'px' - }).show(); + function toggleCoverSize(ratio) { + var coverSize = ui.coverSize == 256 ? 512 : 256, + css = getCSS(coverSize, ratio); + //$cover.animate(css.cover, 250); + $info.animate(css.info, 250); + $image.animate(css.image, 250); + $reflectionImage.animate(css.image, 250); + $reflection.animate(css.reflection, 250); + /* + $reflectionGradient.animate({ + width: iconSize + 'px', + height: iconSize / 2 + 'px' + }, 250); + */ + + oml.UI.set({coverSize: coverSize}); + } + + function updateCover(ratio) { + var css = getCSS(ui.coverSize, ratio); + $image.css(css.image).show(); + $reflectionImage.css(css.image); + $reflection.css(css.reflection).show(); } that.updateElement = function(idOrData, $elements) { @@ -257,10 +274,10 @@ oml.ui.infoView = function(identifyData) { var $mediaButton, isEditable = !data.mainid && data.mediastate == 'available', src = !identifyData - ? '/' + data.id + '/cover256.jpg?' + data.modified + ? '/' + data.id + '/cover512.jpg?' + data.modified : data.cover, ratio = data.coverRatio || oml.config.coverRatio, - size = 256, + size = ui.coverSize, reflectionSize = Math.round(size / 2); $elements.forEach(function($element) { @@ -269,11 +286,14 @@ oml.ui.infoView = function(identifyData) { if ($element == $cover) { - $image = $('') + $image = Ox.Element({ + element: '', + tooltip: '' // TODO + }) .on({ load: function() { - var ratio = $image[0].width / $image[0].height; - updateCover(size, ratio); + ratio = $image[0].width / $image[0].height; + updateCover(ratio); } }) .attr({src: src}) @@ -281,6 +301,11 @@ oml.ui.infoView = function(identifyData) { position: 'absolute' }) .hide() + .bindEvent({ + singleclick: function() { + toggleCoverSize(ratio); + } + }) .appendTo($cover); $reflection = $('