more...
This commit is contained in:
parent
2ee2bc178a
commit
10d2f35b7b
20 changed files with 1334 additions and 629 deletions
|
|
@ -20,8 +20,8 @@ class Changelog(db.Model):
|
|||
editlist name {name: newname}
|
||||
orderlists [name, name, name]
|
||||
removelist name
|
||||
additemtolist listname itemid
|
||||
removeitemfromlist listname itemid
|
||||
addlistitems listname [ids]
|
||||
removelistitems listname [ids]
|
||||
editusername username
|
||||
editcontact string
|
||||
addpeer peerid peername
|
||||
|
|
@ -182,24 +182,17 @@ class Changelog(db.Model):
|
|||
l.remove()
|
||||
return True
|
||||
|
||||
def action_addlistitem(self, user, timestamp, name, itemid):
|
||||
from item.models import Item
|
||||
def action_addlistitems(self, user, timestamp, name, ids):
|
||||
from user.models import List
|
||||
l = List.get(user.id, name)
|
||||
i = Item.get(itemid)
|
||||
if l and i:
|
||||
i.lists.append(l)
|
||||
i.update()
|
||||
l = List.get_or_create(user.id, name)
|
||||
l.add_items(ids)
|
||||
return True
|
||||
|
||||
def action_removelistitem(self, user, timestamp, name, itemid):
|
||||
from item.models import Item
|
||||
def action_removelistitem(self, user, timestamp, name, ids):
|
||||
from user.models import List
|
||||
l = List.get(user.id, name)
|
||||
i = Item.get(itemid)
|
||||
if l and i:
|
||||
i.lists.remove(l)
|
||||
i.update()
|
||||
if l:
|
||||
l.remove_items(ids)
|
||||
return True
|
||||
|
||||
def action_editusername(self, user, timestamp, username):
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from flask import json
|
|||
from oxflask.api import actions
|
||||
from oxflask.shortcuts import returns_json
|
||||
|
||||
from oml import utils
|
||||
import query
|
||||
|
||||
import models
|
||||
|
|
@ -118,6 +117,8 @@ def edit(request):
|
|||
if item and keys and item.json()['mediastate'] == 'available':
|
||||
key = keys[0]
|
||||
print 'update mainid', key, data[key]
|
||||
if key in ('isbn10', 'isbn13'):
|
||||
data[key] = utils.normalize_isbn(data[key])
|
||||
item.update_mainid(key, data[key])
|
||||
response = item.json()
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -233,6 +233,12 @@ class Item(db.Model):
|
|||
else:
|
||||
f.value = '%s:' % p.id
|
||||
db.session.add(f)
|
||||
for l in self.lists:
|
||||
f = Find()
|
||||
f.item_id = self.id
|
||||
f.key = 'list'
|
||||
f.value = l.find_id
|
||||
db.session.add(f)
|
||||
|
||||
def update(self):
|
||||
users = map(str, list(self.users))
|
||||
|
|
|
|||
104
oml/localnodes.py
Normal file
104
oml/localnodes.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vi:si:et:sw=4:sts=4:ts=4
|
||||
|
||||
import socket
|
||||
import thread
|
||||
import json
|
||||
import struct
|
||||
from threading import Thread
|
||||
|
||||
from settings import preferences, server, USER_ID
|
||||
from node.utils import get_public_ipv6
|
||||
|
||||
def can_connect(data):
|
||||
try:
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
s.settimeout(1)
|
||||
s.connect((data['host'], data['port']))
|
||||
s.close()
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
class LocalNodes(Thread):
|
||||
_active = True
|
||||
_nodes = {}
|
||||
|
||||
_BROADCAST = "ff02::1"
|
||||
_PORT = 9851
|
||||
TTL = 2
|
||||
|
||||
def __init__(self, app):
|
||||
self._app = app
|
||||
Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.start()
|
||||
self.host = get_public_ipv6()
|
||||
self.send()
|
||||
|
||||
def send(self):
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
|
||||
ttl = struct.pack('@i', self.TTL)
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl)
|
||||
message = json.dumps({
|
||||
'id': USER_ID,
|
||||
'username': preferences.get('username', 'anonymous'),
|
||||
'host': self.host,
|
||||
'port': server['node_port'],
|
||||
})
|
||||
s.sendto(message + '\0', (self._BROADCAST, self._PORT))
|
||||
|
||||
def receive(self):
|
||||
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
|
||||
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
s.bind(('', self._PORT))
|
||||
group_bin = socket.inet_pton(socket.AF_INET6, self._BROADCAST) + '\0'*4
|
||||
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group_bin)
|
||||
|
||||
while self._active:
|
||||
data, addr = s.recvfrom(1024)
|
||||
while data[-1] == '\0':
|
||||
data = data[:-1] # Strip trailing \0's
|
||||
data = self.validate(data)
|
||||
if data:
|
||||
if data['id'] not in self._nodes:
|
||||
thread.start_new_thread(self.new_node, (data, ))
|
||||
else:
|
||||
print 'UPDATE NODE', data
|
||||
self._nodes[data['id']] = data
|
||||
|
||||
def validate(self, data):
|
||||
try:
|
||||
data = json.loads(data)
|
||||
except:
|
||||
return None
|
||||
for key in ['id', 'username', 'host', 'port']:
|
||||
if key not in data:
|
||||
return None
|
||||
return data
|
||||
|
||||
def get(self, user_id):
|
||||
if user_id in self._nodes:
|
||||
if can_connect(self._nodes[user_id]):
|
||||
return self._nodes[user_id]
|
||||
|
||||
def new_node(self, data):
|
||||
print 'NEW NODE', data
|
||||
if can_connect(data):
|
||||
self._nodes[data['id']] = data
|
||||
with self._app.app_context():
|
||||
import user.models
|
||||
u = user.models.User.get_or_create(data['id'])
|
||||
u.info['username'] = data['username']
|
||||
u.info['local'] = data
|
||||
u.save()
|
||||
self.send()
|
||||
|
||||
def run(self):
|
||||
self.receive()
|
||||
|
||||
def join(self):
|
||||
self._active = False
|
||||
return Thread.join(self)
|
||||
|
|
@ -107,11 +107,8 @@ def start(app):
|
|||
(r"/get/(.*)", ShareHandler, dict(app=app)),
|
||||
(r".*", NodeHandler, dict(app=app)),
|
||||
])
|
||||
|
||||
#tr = WSGIContainer(node_app)
|
||||
#http_server= HTTPServer(tr)
|
||||
http_server.listen(settings.server['node_port'], settings.server['node_address'])
|
||||
host = utils.get_public_ipv4()
|
||||
host = utils.get_public_ipv6()
|
||||
state.online = directory.put(settings.sk, {
|
||||
'host': host,
|
||||
'port': settings.server['node_port']
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# vi:si:et:sw=4:sts=4:ts=4
|
||||
|
||||
import socket
|
||||
import requests
|
||||
from urlparse import urlparse
|
||||
|
||||
def get_public_ipv6():
|
||||
host = ('2a01:4f8:120:3201::3', 25519)
|
||||
|
|
|
|||
25
oml/nodes.py
25
oml/nodes.py
|
|
@ -19,6 +19,7 @@ from changelog import Changelog
|
|||
|
||||
import directory
|
||||
from websocket import trigger_event
|
||||
from localnodes import LocalNodes
|
||||
|
||||
ENCODING='base64'
|
||||
|
||||
|
|
@ -26,8 +27,9 @@ class Node(object):
|
|||
online = False
|
||||
download_speed = 0
|
||||
|
||||
def __init__(self, app, user):
|
||||
self._app = app
|
||||
def __init__(self, nodes, user):
|
||||
self._nodes = nodes
|
||||
self._app = nodes._app
|
||||
self.user_id = user.id
|
||||
key = str(user.id)
|
||||
self.vk = ed25519.VerifyingKey(key, encoding=ENCODING)
|
||||
|
|
@ -35,10 +37,15 @@ class Node(object):
|
|||
|
||||
@property
|
||||
def url(self):
|
||||
if ':' in self.host:
|
||||
url = 'http://[%s]:%s' % (self.host, self.port)
|
||||
local = self.get_local()
|
||||
if local:
|
||||
url = 'http://[%s]:%s' % (local['host'], local['port'])
|
||||
print 'using local peer discovery to access node', url
|
||||
else:
|
||||
url = 'http://%s:%s' % (self.host, self.port)
|
||||
if ':' in self.host:
|
||||
url = 'http://[%s]:%s' % (self.host, self.port)
|
||||
else:
|
||||
url = 'http://%s:%s' % (self.host, self.port)
|
||||
return url
|
||||
|
||||
def resolve_host(self):
|
||||
|
|
@ -51,6 +58,11 @@ class Node(object):
|
|||
self.host = None
|
||||
self.port = 9851
|
||||
|
||||
def get_local(self):
|
||||
if self._nodes and self._nodes._local:
|
||||
return self._nodes._local.get(self.user_id)
|
||||
return None
|
||||
|
||||
def request(self, action, *args):
|
||||
if not self.host:
|
||||
self.resolve_host()
|
||||
|
|
@ -211,6 +223,7 @@ class Nodes(Thread):
|
|||
self._app = app
|
||||
self._q = Queue()
|
||||
self._running = True
|
||||
self._local = LocalNodes(app)
|
||||
Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.start()
|
||||
|
|
@ -238,7 +251,7 @@ class Nodes(Thread):
|
|||
def _add_node(self, user_id):
|
||||
if user_id not in self._nodes:
|
||||
from user.models import User
|
||||
self._nodes[user_id] = Node(self._app, User.get_or_create(user_id))
|
||||
self._nodes[user_id] = Node(self, User.get_or_create(user_id))
|
||||
else:
|
||||
self._nodes[user_id].online = True
|
||||
trigger_event('status', {
|
||||
|
|
|
|||
|
|
@ -144,6 +144,8 @@ class Parser(object):
|
|||
l = self._list.query.filter_by(user_id=p.id, name=name).first()
|
||||
else:
|
||||
l = None
|
||||
if l:
|
||||
v = l.find_id
|
||||
if l and l._query:
|
||||
data = l._query
|
||||
q = self.parse_conditions(data.get('conditions', []),
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ server_defaults = {
|
|||
'port': 9842,
|
||||
'address': '127.0.0.1',
|
||||
'node_port': 9851,
|
||||
'node_address': '::',
|
||||
'node_address': '',
|
||||
'extract_text': True,
|
||||
'directory_service': 'http://[2a01:4f8:120:3201::3]:25519',
|
||||
'lookup_service': 'http://data.openmedialibrary.com',
|
||||
|
|
|
|||
|
|
@ -84,9 +84,9 @@ actions.register(getUsers)
|
|||
|
||||
@returns_json
|
||||
def getLists(request):
|
||||
lists = {}
|
||||
lists = []
|
||||
for u in models.User.query.filter((models.User.peered==True)|(models.User.id==settings.USER_ID)):
|
||||
lists[u.id] = u.lists_json()
|
||||
lists += u.lists_json()
|
||||
return {
|
||||
'lists': lists
|
||||
}
|
||||
|
|
@ -132,28 +132,24 @@ def editList(request):
|
|||
actions.register(editList, cache=False)
|
||||
|
||||
@returns_json
|
||||
def addListItem(request):
|
||||
def addListItems(request):
|
||||
data = json.loads(request.form['data']) if 'data' in request.form else {}
|
||||
l = models.List.get_or_create(data['id'])
|
||||
i = Item.get(data['item'])
|
||||
if l and i:
|
||||
l.items.append(i)
|
||||
models.db.session.add(l)
|
||||
i.update()
|
||||
l = models.List.get_or_create(data['list'])
|
||||
if l:
|
||||
l.add_items(data['items'])
|
||||
return l.json()
|
||||
return {}
|
||||
actions.register(addListItem, cache=False)
|
||||
actions.register(addListItems, cache=False)
|
||||
|
||||
@returns_json
|
||||
def removeListItem(request):
|
||||
def removeListItems(request):
|
||||
data = json.loads(request.form['data']) if 'data' in request.form else {}
|
||||
l = models.List.get(data['id'])
|
||||
i = Item.get(data['item'])
|
||||
if l and i:
|
||||
l.items.remove(i)
|
||||
models.db.session.add(l)
|
||||
i.update()
|
||||
l = models.List.get(data['list'])
|
||||
if l:
|
||||
l.remove_items(data['items'])
|
||||
return l.json()
|
||||
return {}
|
||||
actions.register(removeListItem, cache=False)
|
||||
actions.register(removeListItems, cache=False)
|
||||
|
||||
@returns_json
|
||||
def sortLists(request):
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class User(db.Model):
|
|||
return j
|
||||
|
||||
def check_online(self):
|
||||
return state.nodes.check_online(self.id)
|
||||
return state.nodes and state.nodes.check_online(self.id)
|
||||
|
||||
def lists_json(self):
|
||||
return [l.json() for l in self.lists.order_by('position')]
|
||||
|
|
@ -158,25 +158,39 @@ class List(db.Model):
|
|||
from item.models import Item
|
||||
for item_id in items:
|
||||
i = Item.get(item_id)
|
||||
self.items.add(i)
|
||||
self.items.append(i)
|
||||
i.update()
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
||||
for item_id in items:
|
||||
i = Item.get(item_id)
|
||||
i.update_lists()
|
||||
db.session.commit()
|
||||
if self.user_id == settings.USER_ID:
|
||||
Changelog.record(self.user, 'addlistitems', self.name, items)
|
||||
|
||||
def remove_items(self, items):
|
||||
from item.models import Item
|
||||
for item_id in items:
|
||||
i = Item.get(item_id)
|
||||
self.items.remove(i)
|
||||
i.update()
|
||||
db.session.add(self)
|
||||
db.session.commit()
|
||||
for item_id in items:
|
||||
i = Item.get(item_id)
|
||||
i.update_lists()
|
||||
db.session.commit()
|
||||
if self.user_id == settings.USER_ID:
|
||||
Changelog.record(self.user, 'removelistitems', self.name, items)
|
||||
|
||||
def remove(self):
|
||||
if not self._query:
|
||||
for i in self.items:
|
||||
self.items.remove(i)
|
||||
if not self._query:
|
||||
print 'record change: removelist', self.user, self.name
|
||||
Changelog.record(self.user, 'removelist', self.name)
|
||||
if self.user_id == settings.USER_ID:
|
||||
Changelog.record(self.user, 'removelist', self.name)
|
||||
db.session.delete(self)
|
||||
db.session.commit()
|
||||
|
||||
|
|
@ -184,10 +198,21 @@ class List(db.Model):
|
|||
def public_id(self):
|
||||
id = ''
|
||||
if self.user_id != settings.USER_ID:
|
||||
id += self.user_id
|
||||
id = '%s:%s' % (id, self.name)
|
||||
id += self.user.nickname
|
||||
id = u'%s:%s' % (id, self.name)
|
||||
return id
|
||||
|
||||
@property
|
||||
def find_id(self):
|
||||
id = ''
|
||||
if self.user_id != settings.USER_ID:
|
||||
id += self.user_id
|
||||
id = u'%s:%s' % (id, self.id)
|
||||
return id
|
||||
|
||||
def __repr__(self):
|
||||
return self.public_id.encode('utf-8')
|
||||
|
||||
def items_count(self):
|
||||
from item.models import Item
|
||||
if self._query:
|
||||
|
|
@ -199,6 +224,7 @@ class List(db.Model):
|
|||
def json(self):
|
||||
r = {
|
||||
'id': self.public_id,
|
||||
'user': self.user.nickname if self.user_id != settings.USER_ID else settings.preferences['username'],
|
||||
'name': self.name,
|
||||
'index': self.position,
|
||||
'items': self.items_count(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue