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 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import item.api
import user.api

View file

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

View file

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

View file

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

View file

@ -19,14 +19,6 @@ def parse(data):
query[key] = data[key]
#print 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:
query['qs'] = order(query['qs'], query['sort'])
return query

View file

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

View file

@ -2,7 +2,6 @@
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os
from datetime import datetime
import zipfile
import mimetypes
@ -10,7 +9,7 @@ from StringIO import StringIO
import Image
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
import settings

View file

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

View file

@ -2,12 +2,9 @@
# vi:si:et:sw=4:sts=4:ts=4
import os
import sys
import tornado
from tornado.web import StaticFileHandler, Application, FallbackHandler
from tornado.wsgi import WSGIContainer
from tornado.web import Application
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop, PeriodicCallback
import settings
@ -104,23 +101,26 @@ class ShareHandler(tornado.web.RequestHandler):
self.finish()
def start(app):
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'])
def publish_node():
host = utils.get_public_ipv6()
state.online = directory.put(settings.sk, {
'host': host,
'port': settings.server['node_port'],
'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

View file

@ -11,10 +11,3 @@ def get_public_ipv6():
s.close()
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 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement
import inspect
import sys
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__)), '..'))
PID = sys.argv[2] if len(sys.argv) > 2 else None
state.main = IOLoop.instance()
static_path = os.path.join(root_dir, 'static')
options = {
@ -37,11 +35,15 @@ def run():
]
http_server = HTTPServer(Application(handlers, **options))
http_server.listen(settings.server['port'], settings.server['address'])
if PID:
with open(PID, 'w') as pid:
pid.write('%s' % os.getpid())
state.main = IOLoop.instance()
def start_node():
import user
import downloads

View file

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

View file

@ -1,15 +1,16 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os
from copy import deepcopy
import subprocess
import json
from flask import json
from oxflask.api import actions
from oxflask.shortcuts import returns_json
import models
from item.models import Item
from utils import get_position_by_id
@ -176,6 +177,9 @@ actions.register(editUser, cache=False)
@returns_json
def requestPeering(request):
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'])
state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'requestPeering', data.get('message', ''))
@ -185,6 +189,9 @@ actions.register(requestPeering, cache=False)
@returns_json
def acceptPeering(request):
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'])
state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'acceptPeering', data.get('message', ''))
@ -194,6 +201,9 @@ actions.register(acceptPeering, cache=False)
@returns_json
def rejectPeering(request):
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'])
state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'rejectPeering', data.get('message', ''))
@ -203,6 +213,9 @@ actions.register(rejectPeering, cache=False)
@returns_json
def removePeering(request):
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'])
state.nodes.queue('add', u.id)
state.nodes.queue(u.id, 'removePeering', data.get('message', ''))
@ -212,8 +225,40 @@ actions.register(removePeering, cache=False)
@returns_json
def cancelPeering(request):
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'])
state.nodes.queue('add', p.id)
state.nodes.queue(p.id, 'cancelPeering', data.get('message', ''))
return {}
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.ioloop import IOLoop
from Queue import Queue
import urllib2
import os
from contextlib import closing
import json
from threading import Thread
@ -19,9 +16,9 @@ class Background:
def __init__(self, handler):
self.handler = handler
self.main = IOLoop.instance()
self.q = Queue()
self.connected = True
self.main = IOLoop.instance()
def worker(self):
while self.connected: