import/export

This commit is contained in:
j 2014-05-17 02:14:15 +02:00
parent ec83ec052c
commit dbfdd50a29
16 changed files with 120 additions and 84 deletions

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import item.api import item.api
import user.api import user.api

View file

@ -59,14 +59,16 @@ class Changelog(db.Model):
@classmethod @classmethod
def apply_changes(cls, user, changes): def apply_changes(cls, user, changes):
for change in changes: for change in changes:
if not Changelog.apply_change(user, change): if not Changelog.apply_change(user, change, trigger=False):
print 'FAIL', change print 'FAIL', change
break break
return False return False
if changes:
trigger_event('change', {});
return True return True
@classmethod @classmethod
def apply_change(cls, user, change, rebuild=False): def apply_change(cls, user, change, rebuild=False, trigger=True):
revision, timestamp, sig, data = change revision, timestamp, sig, data = change
last = Changelog.query.filter_by(user_id=user.id).order_by('-revision').first() last = Changelog.query.filter_by(user_id=user.id).order_by('-revision').first()
next_revision = last.revision + 1 if last else 0 next_revision = last.revision + 1 if last else 0
@ -87,6 +89,8 @@ class Changelog(db.Model):
print 'change applied' print 'change applied'
db.session.add(c) db.session.add(c)
db.session.commit() db.session.commit()
if trigger:
trigger_event('change', {});
return True return True
else: else:
print 'INVLAID SIGNATURE ON CHANGE', change print 'INVLAID SIGNATURE ON CHANGE', change

View file

@ -36,7 +36,7 @@ def put(sk, data):
'X-Ed25519-Signature': sig 'X-Ed25519-Signature': sig
} }
try: try:
r = requests.put(url, data, headers=headers) r = requests.put(url, data, headers=headers, timeout=2)
except: except:
import traceback import traceback
print 'directory.put failed:', data print 'directory.put failed:', data

View file

@ -2,9 +2,7 @@
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division from __future__ import division
from datetime import datetime import json
from flask import json
from oxflask.api import actions from oxflask.api import actions
from oxflask.shortcuts import returns_json from oxflask.shortcuts import returns_json
@ -12,8 +10,6 @@ import query
import models import models
import settings import settings
from changelog import Changelog
import re
import state import state
import meta import meta
@ -35,14 +31,16 @@ def find(request):
qs = models.Find.query.filter_by(key=q['group']) qs = models.Find.query.filter_by(key=q['group'])
if items: if items:
qs = qs.filter(models.Find.item_id.in_(items)) qs = qs.filter(models.Find.item_id.in_(items))
for f in qs.values('value', 'findvalue'): for f in qs.values('value', 'findvalue'):
value = f[0] value = f[0]
findvalue = f[1] findvalue = f[1]
if findvalue not in groups: if findvalue not in groups:
groups[findvalue] = 0 groups[findvalue] = 0
groups[findvalue] += 1 groups[findvalue] += 1
names[findvalue] = value names[findvalue] = value
g = [{'name': names[k], 'items': groups[k]} for k in groups] g = [{'name': names[k], 'items': groups[k]} for k in groups]
else:
g = []
if 'sort' in q: if 'sort' in q:
g.sort(key=lambda k: k[q['sort'][0]['key']]) g.sort(key=lambda k: k[q['sort'][0]['key']])
if q['sort'][0]['operator'] == '-': if q['sort'][0]['operator'] == '-':

View file

@ -19,14 +19,6 @@ def parse(data):
query[key] = data[key] query[key] = data[key]
#print data #print data
query['qs'] = oxflask.query.Parser(models.Item).find(data) query['qs'] = oxflask.query.Parser(models.Item).find(data)
if 'query' in query and 'conditions' in query['query'] and query['query']['conditions']:
conditions = query['query']['conditions']
condition = conditions[0]
if condition['key'] == '*':
value = condition['value'].lower()
query['qs'] = models.Item.query.join(
models.Find, models.Find.item_id==models.Item.id).filter(
models.Find.value.contains(value))
if not 'group' in query: if not 'group' in query:
query['qs'] = order(query['qs'], query['sort']) query['qs'] = order(query['qs'], query['sort'])
return query return query

View file

@ -18,6 +18,7 @@ from changelog import Changelog
import media import media
from websocket import trigger_event from websocket import trigger_event
import state
extensions = ['epub', 'pdf', 'txt'] extensions = ['epub', 'pdf', 'txt']
@ -62,9 +63,6 @@ def run_scan():
if ext in extensions: if ext in extensions:
books.append(f) books.append(f)
trigger_event('scan', {
'progress': [0, len(books)],
})
position = 0 position = 0
added = 0 added = 0
for f in ox.sorted_strings(books): for f in ox.sorted_strings(books):
@ -95,33 +93,25 @@ def run_scan():
item.added = datetime.now() item.added = datetime.now()
item.scrape() item.scrape()
added += 1 added += 1
trigger_event('scan', { trigger_event('change', {})
'added': added,
'progress': [position, len(books)],
'path': path,
})
trigger_event('scan', {
'progress': [position, len(books)],
'added': added,
'status': {'code': 200, 'text': ''}
})
def run_import(options=None): def run_import(options=None):
options = options or {} options = options or {}
with app.app_context(): with app.app_context():
prefs = settings.preferences prefs = settings.preferences
prefix = options.get('path', os.path.expanduser(prefs['importPath'])) prefix = os.path.expanduser(options.get('path', prefs['importPath']))
prefix_books = os.path.join(os.path.expanduser(prefs['libraryPath']), 'Books/')
prefix_imported = os.path.join(prefix_books, 'Imported/')
if not prefix[-1] == '/': if not prefix[-1] == '/':
prefix += '/' prefix += '/'
prefix_books = os.path.join(os.path.expanduser(prefs['libraryPath']), 'Books/')
prefix_imported = os.path.join(prefix_books, 'Imported/')
if not os.path.exists(prefix): if not os.path.exists(prefix):
trigger_event('import', { trigger_event('activity', {
'activity': 'import',
'progress': [0, 0], 'progress': [0, 0],
'status': {'code': 404, 'text': 'path not found'} 'status': {'code': 404, 'text': 'path not found'}
}) })
state.activity = {}
user = User.get_or_create(settings.USER_ID) user = User.get_or_create(settings.USER_ID)
listname = options.get('list') listname = options.get('list')
if listname: if listname:
@ -138,13 +128,17 @@ def run_import(options=None):
if ext in extensions: if ext in extensions:
books.append(f) books.append(f)
trigger_event('import', { state.activity = {
'activity': 'import',
'progress': [0, len(books)], 'progress': [0, len(books)],
}) }
trigger_event('activity', state.activity)
position = 0 position = 0
added = 0 added = 0
for f in ox.sorted_strings(books): for f in ox.sorted_strings(books):
position += 1 position += 1
if not os.path.exists(f):
continue
id = media.get_id(f) id = media.get_id(f)
file = File.get(id) file = File.get(id)
path = f[len(prefix):] path = f[len(prefix):]
@ -180,16 +174,20 @@ def run_import(options=None):
if listname: if listname:
listitems.append(item.id) listitems.append(item.id)
added += 1 added += 1
trigger_event('import', { state.activity = {
'activity': 'import',
'progress': [position, len(books)], 'progress': [position, len(books)],
'path': path, 'path': path,
'added': added, 'added': added,
}) }
trigger_event('activity', state.activity)
if listname: if listname:
l = List.get_or_create(settings.USER_ID, listname) l = List.get_or_create(settings.USER_ID, listname)
l.add_items(listitems) l.add_items(listitems)
trigger_event('import', { trigger_event('activity', {
'activity': 'import',
'progress': [position, len(books)], 'progress': [position, len(books)],
'status': {'code': 200, 'text': ''}, 'status': {'code': 200, 'text': ''},
'added': added, 'added': added,
}) })
state.activity = {}

View file

@ -2,7 +2,6 @@
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division from __future__ import division
import os
from datetime import datetime from datetime import datetime
import zipfile import zipfile
import mimetypes import mimetypes
@ -10,7 +9,7 @@ from StringIO import StringIO
import Image import Image
from flask import Blueprint from flask import Blueprint
from flask import json, request, make_response, abort, send_file from flask import make_response, abort, send_file
from covers import covers from covers import covers
import settings import settings

View file

@ -29,7 +29,7 @@ def can_connect(data):
def get_interface(): def get_interface():
interface = '' interface = ''
if sys.platform == 'darwin': if sys.platform == 'darwin':
#cmd = ['netstat', '-rn'] #cmd = ['/usr/sbin/netstat', '-rn']
cmd = ['/sbin/route', '-n', 'get', 'default'] cmd = ['/sbin/route', '-n', 'get', 'default']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE) p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
stdout, stderr = p.communicate() stdout, stderr = p.communicate()
@ -92,7 +92,8 @@ class LocalNodes(Thread):
data = data[:-1] # Strip trailing \0's data = data[:-1] # Strip trailing \0's
data = self.verify(data) data = self.verify(data)
if data: if data:
print addr #fixme use local link address
#print addr
if data['id'] != USER_ID: if data['id'] != USER_ID:
if data['id'] not in self._nodes: if data['id'] not in self._nodes:
thread.start_new_thread(self.new_node, (data, )) thread.start_new_thread(self.new_node, (data, ))

View file

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import settings import settings
from changelog import Changelog from changelog import Changelog
from user.models import User from user.models import User

View file

@ -2,12 +2,9 @@
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import os import os
import sys
import tornado import tornado
from tornado.web import StaticFileHandler, Application, FallbackHandler from tornado.web import Application
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop, PeriodicCallback
import settings import settings
@ -104,23 +101,26 @@ class ShareHandler(tornado.web.RequestHandler):
self.finish() self.finish()
def start(app): def publish_node():
application = tornado.web.Application([
(r"/get/(.*)", ShareHandler, dict(app=app)),
(r".*", NodeHandler, dict(app=app)),
])
if not os.path.exists(settings.ssl_cert_path):
settings.server['cert'] = cert.generate_ssl()
http_server = tornado.httpserver.HTTPServer(application, ssl_options={
"certfile": settings.ssl_cert_path,
"keyfile": settings.ssl_key_path
})
http_server.listen(settings.server['node_port'], settings.server['node_address'])
host = utils.get_public_ipv6() host = utils.get_public_ipv6()
state.online = directory.put(settings.sk, { state.online = directory.put(settings.sk, {
'host': host, 'host': host,
'port': settings.server['node_port'], 'port': settings.server['node_port'],
'cert': settings.server['cert'] 'cert': settings.server['cert']
}) })
def start(app):
application = Application([
(r"/get/(.*)", ShareHandler, dict(app=app)),
(r".*", NodeHandler, dict(app=app)),
])
if not os.path.exists(settings.ssl_cert_path):
settings.server['cert'] = cert.generate_ssl()
http_server = HTTPServer(application, ssl_options={
"certfile": settings.ssl_cert_path,
"keyfile": settings.ssl_key_path
})
http_server.listen(settings.server['node_port'], settings.server['node_address'])
state.main.add_callback(publish_node)
return http_server return http_server

View file

@ -11,10 +11,3 @@ def get_public_ipv6():
s.close() s.close()
return ip return ip
def get_public_ipv4():
host = ('10.0.3.1', 25519)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(host)
ip = s.getsockname()[0]
s.close()
return ip

View file

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement from __future__ import division, with_statement
import inspect import inspect
import sys import sys
import json import json

View file

@ -19,8 +19,6 @@ def run():
root_dir = os.path.normpath(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..')) root_dir = os.path.normpath(os.path.join(os.path.abspath(os.path.dirname(__file__)), '..'))
PID = sys.argv[2] if len(sys.argv) > 2 else None PID = sys.argv[2] if len(sys.argv) > 2 else None
state.main = IOLoop.instance()
static_path = os.path.join(root_dir, 'static') static_path = os.path.join(root_dir, 'static')
options = { options = {
@ -37,11 +35,15 @@ def run():
] ]
http_server = HTTPServer(Application(handlers, **options)) http_server = HTTPServer(Application(handlers, **options))
http_server.listen(settings.server['port'], settings.server['address']) http_server.listen(settings.server['port'], settings.server['address'])
if PID: if PID:
with open(PID, 'w') as pid: with open(PID, 'w') as pid:
pid.write('%s' % os.getpid()) pid.write('%s' % os.getpid())
state.main = IOLoop.instance()
def start_node(): def start_node():
import user import user
import downloads import downloads

View file

@ -3,6 +3,8 @@ nodes = False
main = None main = None
online = False online = False
activity = {}
def user(): def user():
import settings import settings
import user.models import user.models

View file

@ -1,15 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os import os
from copy import deepcopy from copy import deepcopy
import subprocess
import json
from flask import json
from oxflask.api import actions from oxflask.api import actions
from oxflask.shortcuts import returns_json from oxflask.shortcuts import returns_json
import models import models
from item.models import Item
from utils import get_position_by_id from utils import get_position_by_id
@ -176,6 +177,9 @@ actions.register(editUser, cache=False)
@returns_json @returns_json
def requestPeering(request): def requestPeering(request):
data = json.loads(request.form['data']) if 'data' in request.form else {} data = json.loads(request.form['data']) if 'data' in request.form else {}
if len(data.get('id', '')) != 43:
print 'invalid user id'
return {}
p = models.User.get_or_create(data['id']) p = models.User.get_or_create(data['id'])
state.nodes.queue('add', p.id) state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'requestPeering', data.get('message', '')) state.nodes.queue(p.id, 'requestPeering', data.get('message', ''))
@ -185,6 +189,9 @@ actions.register(requestPeering, cache=False)
@returns_json @returns_json
def acceptPeering(request): def acceptPeering(request):
data = json.loads(request.form['data']) if 'data' in request.form else {} data = json.loads(request.form['data']) if 'data' in request.form else {}
if len(data.get('id', '')) != 43:
print 'invalid user id'
return {}
p = models.User.get_or_create(data['id']) p = models.User.get_or_create(data['id'])
state.nodes.queue('add', p.id) state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'acceptPeering', data.get('message', '')) state.nodes.queue(p.id, 'acceptPeering', data.get('message', ''))
@ -194,6 +201,9 @@ actions.register(acceptPeering, cache=False)
@returns_json @returns_json
def rejectPeering(request): def rejectPeering(request):
data = json.loads(request.form['data']) if 'data' in request.form else {} data = json.loads(request.form['data']) if 'data' in request.form else {}
if len(data.get('id', '')) != 43:
print 'invalid user id'
return {}
p = models.User.get_or_create(data['id']) p = models.User.get_or_create(data['id'])
state.nodes.queue('add', p.id) state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'rejectPeering', data.get('message', '')) state.nodes.queue(p.id, 'rejectPeering', data.get('message', ''))
@ -203,6 +213,9 @@ actions.register(rejectPeering, cache=False)
@returns_json @returns_json
def removePeering(request): def removePeering(request):
data = json.loads(request.form['data']) if 'data' in request.form else {} data = json.loads(request.form['data']) if 'data' in request.form else {}
if len(data.get('id', '')) != 43:
print 'invalid user id'
return {}
u = models.User.get_or_create(data['id']) u = models.User.get_or_create(data['id'])
state.nodes.queue('add', u.id) state.nodes.queue('add', u.id)
state.nodes.queue(u.id, 'removePeering', data.get('message', '')) state.nodes.queue(u.id, 'removePeering', data.get('message', ''))
@ -212,8 +225,40 @@ actions.register(removePeering, cache=False)
@returns_json @returns_json
def cancelPeering(request): def cancelPeering(request):
data = json.loads(request.form['data']) if 'data' in request.form else {} data = json.loads(request.form['data']) if 'data' in request.form else {}
if len(data.get('id', '')) != 43:
print 'invalid user id'
return {}
p = models.User.get_or_create(data['id']) p = models.User.get_or_create(data['id'])
state.nodes.queue('add', p.id) state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'cancelPeering', data.get('message', '')) state.nodes.queue(p.id, 'cancelPeering', data.get('message', ''))
return {} return {}
actions.register(cancelPeering, cache=False) actions.register(cancelPeering, cache=False)
@returns_json
def getActivity(request):
return state.activity
actions.register(getActivity, cache=False)
@returns_json
def selectFolder(request):
data = json.loads(request.form['data']) if 'data' in request.form else {}
cmd = ['./ctl', 'ui', 'folder']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
path = stdout.decode('utf-8').strip()
return {
'path': path
}
actions.register(selectFolder, cache=False)
@returns_json
def selectFile(request):
data = json.loads(request.form['data']) if 'data' in request.form else {}
cmd = ['./ctl', 'ui', 'file']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
stdout, stderr = p.communicate()
path = stdout.decode('utf-8').strip()
return {
'path': path
}
actions.register(selectFile, cache=False)

View file

@ -5,9 +5,6 @@ from __future__ import division
from tornado.websocket import WebSocketHandler from tornado.websocket import WebSocketHandler
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
from Queue import Queue from Queue import Queue
import urllib2
import os
from contextlib import closing
import json import json
from threading import Thread from threading import Thread
@ -19,9 +16,9 @@ class Background:
def __init__(self, handler): def __init__(self, handler):
self.handler = handler self.handler = handler
self.main = IOLoop.instance()
self.q = Queue() self.q = Queue()
self.connected = True self.connected = True
self.main = IOLoop.instance()
def worker(self): def worker(self):
while self.connected: while self.connected: