Adding WOT API to RPC to enable 3rd party apps like merkato

This commit is contained in:
Kevin F 2022-10-14 18:26:07 +00:00
parent 4572f255fb
commit 9501d73546
8 changed files with 98 additions and 13 deletions

View File

@ -5,8 +5,7 @@ Default example plugin for devs or to test blocks
import sys import sys
import os import os
import locale import locale
from threading import Thread from secrets import randbelow
from time import sleep
import cherrypy import cherrypy
@ -14,8 +13,11 @@ locale.setlocale(locale.LC_ALL, '')
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)))
# import after path insert # import after path insert
from logger import log as logging
from utils import identifyhome from utils import identifyhome
from onionrthreads import add_onionr_thread from onionrthreads import add_onionr_thread
import config
from onionrplugins.pluginapis import plugin_apis
""" """
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -45,6 +47,9 @@ jsonrpc.manager.json = ujson
# RPC modules map Onionr APIs to the RPC dispacher # RPC modules map Onionr APIs to the RPC dispacher
from rpc import blocks, pluginrpcmethods from rpc import blocks, pluginrpcmethods
from rpc.addmodule import add_module_to_api
plugin_apis['rpc.add_module_to_api'] = add_module_to_api
class OnionrRPC(object): class OnionrRPC(object):
@cherrypy.expose @cherrypy.expose
@ -58,16 +63,37 @@ class OnionrRPC(object):
def on_afterinit(api, data=None): def on_afterinit(api, data=None):
def ping():
return "pong"
dispatcher['ping'] = ping
pluginrpcmethods.add_plugin_rpc_methods() pluginrpcmethods.add_plugin_rpc_methods()
def _gen_random_loopback():
return f'127.{randbelow(256)}.{randbelow(256)}.{randbelow(256)}'
def on_init(api, data=None): def on_init(api, data=None):
config = { bind_config = {}
#'server.socket_file': socket_file_path, if config.get('rpc.use_sock_file', True, save=True):
'server.socket_port': 0, bind_config['server.socket_file'] = config.get(
'rpc.sock_file_path', socket_file_path, save=True)
# create base dir if it doesn't exist
os.makedirs(
os.path.dirname(config.get('rpc.sock_file_path', socket_file_path)), exist_ok=True)
else:
# Set default bind TCP address, if not set
# We use a random loopback address to avoid browser side channel attacks
# and let the OS pick a port (0)
bind_config['server.socket_host'] = config.get(
'rpc.bind_host', _gen_random_loopback(), save=True)
bind_config['server.socket_port'] = config.get('rpc.bind_port', 0)
cherrpy_config = bind_config | {
'engine.autoreload.on': False 'engine.autoreload.on': False
} }
cherrypy.config.update(config) cherrypy.config.update(cherrpy_config)
logging.info("Starting RPC Server")
add_onionr_thread( add_onionr_thread(
cherrypy.quickstart, 5, 'OnionrRPCServer', cherrypy.quickstart, 5, 'OnionrRPCServer',

View File

@ -0,0 +1,11 @@
from types import ModuleType
from jsonrpc import dispatcher
def add_module_to_api(module: ModuleType):
prefix = f"{module.__name__}."
for attr in dir(module):
attr = getattr(module, attr)
if callable(attr):
if hasattr(attr, 'json_compatible'):
dispatcher[prefix + attr.__name__] = attr

View File

@ -5,4 +5,8 @@ from onionrplugins.pluginapis import plugin_apis
def add_plugin_rpc_methods(): def add_plugin_rpc_methods():
for method in plugin_apis: for method in plugin_apis:
dispatcher[method] = plugin_apis[method] try:
if plugin_apis[method].json_compatible:
dispatcher[method] = plugin_apis[method]
except AttributeError:
pass

View File

@ -1 +1,31 @@
import tty import tty
import sys
import subprocess
def do_quit(): raise KeyboardInterrupt
def list_idens():
print('Listing identities')
main_menu = {
'l': (list_idens, 'list identities'),
'q': (do_quit, 'quit CLI')
}
def main_ui():
tty.setraw(sys.stdin)
while True:
# move cursor to the beginning
print('\r', end='')
key = sys.stdin.read(1)
try:
main_menu[key][1]()
except KeyError:
pass
except KeyboardInterrupt:
break
subprocess.Popen(['reset'], stdout=subprocess.PIPE)

View File

@ -37,15 +37,16 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
plugin_name = 'wot' plugin_name = 'wot'
PLUGIN_VERSION = '0.0.1' PLUGIN_VERSION = '0.0.1'
from wot.identity import identities from wot.identity import identities
from cli import main_ui
from onionrplugins import plugin_apis
import wot
from wot.loadfromblocks import load_identities_from_blocks from wot.loadfromblocks import load_identities_from_blocks
from wot.identity import get_distance
def on_init(api, data=None): def on_init(api, data=None):
logging.info( logging.info(
f"Web of Trust Plugin v{PLUGIN_VERSION} enabled") f"Web of Trust Plugin v{PLUGIN_VERSION} enabled")
#onionrplugins.plugin_apis['wot'] = wot_test
plugin_apis['wot.get_distance'] = get_distance
list( list(
map( map(
@ -53,6 +54,8 @@ def on_init(api, data=None):
load_identities_from_blocks()) load_identities_from_blocks())
) )
plugin_apis['rpc.add_module_to_api'](wot)
def on_wot_cmd(api, data=None): def on_wot_cmd(api, data=None):
return main_ui()

View File

@ -5,4 +5,5 @@ from typing import TYPE_CHECKING, Set
from .identity import Identity from .identity import Identity
from .getbykey import get_identity_by_key from .getbykey import get_identity_by_key
from .identity import identities from .identity import identities
from .identity.identityset import serialize_identity_set

View File

@ -17,3 +17,5 @@ def get_identity_by_key(
if bytes(identity.key) == bytes(key): if bytes(identity.key) == bytes(key):
return identity return identity
raise KeyError("Identity not found") raise KeyError("Identity not found")
get_identity_by_key

View File

@ -27,4 +27,12 @@ class IdentitySet(set):
# Set of identites within N-distance trust # Set of identites within N-distance trust
identities = IdentitySet() identities = IdentitySet()
def serialize_identity_set():
serialized_idens = []
for identity in list(identities):
serialized_idens.append(identity.serialize())
return serialized_idens
serialize_identity_set.json_compatible = True