LINUX.ORG.RU

json-rpc на python

 , ,


0

1

Нужно написать клиент-серверное приложение именно на python.

В чём функциональность заключается, не особо важно... особой роли не играет. Хочу использовать RPC - вижу много разных стандартов - больше всего нравится json-rpc (вроде бы и компактный, и парсится легко).

В стандартной библиотеке есть модуль json - если ему передать json-строку по типу:

 {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}

То на выходе получается словарь jsondict:

{'params': [42, 23], 'jsonrpc': '2.0', 'method': 'subtract', 'id': 1}

То есть даже парсить его вручную не надо... есть стандартный библиотечный модуль. Удобно. Я получаю jsondict['method'] - строка, содержащая имя метода, jsondict['params'] - список параметров, ну и соответственно jsondict['id']

Вопрос - как мне этот метод _безопасно_ запустить? Ну например предыстория такая... через socket s клиент соединился с сервером, отправляет ему s.send(somejsonstring.encode('ascii')), например... сервер получает эту строку и парсит, получает словарь.

Я могу, например, использовать:

eval(methodstring + '(' + param1 + ',' + param2 + .... + paramN + ')'

Но eval использовать как-то боязно. :) Вдруг кто подкинет строчку в названии метода 'import os; os.system(«rm -rf /*»)' ?

Как сделать это безопасно?.. запустить метод (если он существует), зная его имя в виде строки и список параметров...?

★★★★★

Последнее исправление: BattleCoder (всего исправлений: 1)

Как сделать это безопасно?

не использовать eval

в питон есть такая интересная фишка:


def a(*args):
    pass

def b(*args):
    pass

def c(*args):
    pass


functions = {'a':a, 'b': b, 'c': c}

def myfunc(*args, **kwargs):
    if 'func_name' in kwargs:
        if kwargs['func_name'] in functions.keys():
            functions[kwargs['func_name']](kwargs['arguments'])

AGUtilities ★★★
()
Ответ на: комментарий от AGUtilities

хотя, очевидно, что это можно было бы сделать и без звёздочных параметров

def myfunc(funcname, args):
    if funcname in functions.keys():
        functions[funcname](args)

а вот, как раз, функции a,b и c, могут, с помощью звёздочных параметров получать любвые данные

AGUtilities ★★★
()
Последнее исправление: AGUtilities (всего исправлений: 1)

сделать класс у которого if hassattr(attrname, obj): ... Или просто getattr(attrname, obj)(*args, **kwargs). Я бы ещё на всякий случай добавил проверку assert not attrname.startswith('_'), а то мало ли ...

true_admin ★★★★★
()
Ответ на: комментарий от AGUtilities

То есть мне этот словарь объявить где-нибудь с указателями на функции... и на него обращаться?.. мм, вроде просто. и правда, почему я так не догадался? :) вечер уже..

BattleCoder ★★★★★
() автор топика
Ответ на: комментарий от true_admin

да... а так даже ещё проще и чище код будет... правда догадаться чуть сложнее. думаю, этот вариант подойдёт

BattleCoder ★★★★★
() автор топика
Ответ на: комментарий от true_admin

Проверил... Работает. То, что нужно.

Думаю, этот метод вполне подойдёт - я всё равно собирался все подобные методы хранить в классе - просто так удобнее будет.

Но чисто любительский интерес. :) а если я объявляю функцию def function: return 0 где-нить в глобальном пространстве - я ведь тоже по идее могу её найти как-то через getattr? только obj нужно нужный подставить...

BattleCoder ★★★★★
() автор топика
Ответ на: комментарий от AGUtilities

для этого есть декоратор @property

@property совсем не то делает, ТС нужны функции с аргументами, а не поле при обращении к которому будет дёргаться соответствующая функция. Хотя идея задать доступные через rpc декораторы может быть неплохой. Даже проверку аргументов можно сделать...

true_admin ★★★★★
()
Ответ на: комментарий от BattleCoder

я ведь тоже по идее могу её найти

dir() итп есть.

true_admin ★★★★★
()

больше всего нравится json-rpc (вроде бы и компактный, и парсится легко).

В стандартной библиотеке есть модуль json

А ещё в стандартной библиотеке есть модуль xmlrpclib. С ним даже xml парсится легко.

anonymous
()
Ответ на: комментарий от anonymous

ну в принципе я ещё перед выбором - брать готовый xmlrpc, или брать json и допиливать...

для меня особой разницы нет, преимущество json вижу в том, что покомпактнее... трафик меньше кушать будет.

BattleCoder ★★★★★
() автор топика
Ответ на: комментарий от BattleCoder

для меня особой разницы нет, преимущество json вижу в том, что покомпактнее... трафик меньше кушать будет.

Да, есть такое. С другой стороны, ты можешь впилить компрессию, хоть через gzip, хоть через tls. Примеров в гугле полно, да и сама задача довольно простая.

Пилить свой json-rpc стоит, если есть задача обучения, имхо.

anonymous
()
Ответ на: комментарий от anonymous

именно в этом и задача, вы угадали...

BattleCoder ★★★★★
() автор топика

Собственно, я снова в ступоре.

json-rpc-сервер я написал, и запросы он умеет правильно обрабатывать. При каждом соединении клиента создаётся новый поток, этот поток запускает специальный класс, который парсит json-строку, и в зависимости от этого запускает методы (другого класса) в коде python. Возможно, это не лучшее решение, но оно работает, и я не хочу его менять.

Разумеется, мне нужно написать не 'hello from server world'-приложение, а кое-что более серьёзное. Нужно написать чат (да, велосипед, но так с меня требуют. :) в образовательных целях так сказать).

Данные надо хранить в sqlite (не принципиально, но удобный вариант, менять не буду). Например, данные регистрации пользователей (имена и пароли).

Начиная реализовывать первый же метод, отвечающий за регистрацию нового пользователя, столкнулся с неприятностью:

sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread.The object was created in thread id 4364 and this is thread id 856

Собственно, ругается, что sqlite объект создался из одного треда, и пытается получить к нему доступ из другого.

Собственно, чат предполагает одновременное взаимодействие множества пользователей, поэтому мне нужна многопоточность. Например, один клиент регистрируется, другой в этот момент логинится, третий в этот момент пишет сообщение, четвёртый читает ленту сообщений в комнате. И, разумеется, пространство данных для всех компонентов приложения должно быть общим - список пользователей должен быть доступен для всех, пользователи должны между собой общаться, читать ВСЕ сообщения (а не только свои), и т.п...

Как мне всё это реализовать? Мозги путаются %( а динамическая типизация питона делу не помогает, а только ещё сильнее мешает. Посоветуйте, как продумать архитектуру такого приложения (интересует не код, а скорее «рецепт»), какие классы/модули/объекты создать, и что они должны делать?

Вот я, например, создал сервер. И ещё один класс (внутри сервера) парсит json и запускает удалённые методы (методы находятся в третьем классе, чтобы не было мусора) Что дальше? :)

BattleCoder ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.