progress commit on python support

This commit is contained in:
Vincent Castellano 2015-05-02 21:32:30 -07:00
parent 2a99ce59d1
commit a240097bbb
3 changed files with 398 additions and 326 deletions

3
main.c
View File

@ -471,6 +471,9 @@ void usage (void) {
#ifdef USE_LUA #ifdef USE_LUA
printf (" -s lua script file\n"); printf (" -s lua script file\n");
#endif #endif
#ifdef USE_PYTHON
printf (" -Z python script file\n");
#endif
printf (" -W send dialog_list query and wait for answer before reading input\n"); printf (" -W send dialog_list query and wait for answer before reading input\n");
printf (" -C disable color output\n"); printf (" -C disable color output\n");
printf (" -R disable readline\n"); printf (" -R disable readline\n");

View File

@ -47,299 +47,331 @@ extern int verbosity;
extern struct tgl_state *TLS; extern struct tgl_state *TLS;
static int have_file; static int have_file;
//
//void push_user (tgl_peer_t *P); // Python update function callables
//void push_peer (tgl_peer_id_t id, tgl_peer_t *P); PyObject *_py_binlog_end;
// PyObject *_py_diff_end;
//void lua_add_string_field (const char *name, const char *value) { PyObject *_py_our_id;
// assert (name && strlen (name)); PyObject *_py_new_msg;
// if (!value || !strlen (value)) { return; } PyObject *_py_secret_chat_update;
// my_lua_checkstack (luaState, 3); PyObject *_py_user_update;
// lua_pushstring (luaState, name); PyObject *_py_chat_update;
// lua_pushstring (luaState, value);
// lua_settable (luaState, -3); // Python callback callables
//} PyObject *_py_empty_cb;
// PyObject *_py_contact_list_cb;
//void lua_add_string_field_arr (int num, const char *value) { PyObject *_py_dialog_list_cb;
// if (!value || !strlen (value)) { return; } PyObject *_py_msg_cb;
// my_lua_checkstack (luaState, 3); PyObject *_py_msg_list_cb;
// lua_pushnumber (luaState, num); PyObject *_py_file_cb;
// lua_pushstring (luaState, value); PyObject *_py_chat_cb;
// lua_settable (luaState, -3); PyObject *_py_secret_chat_cb;
//} PyObject *_py_user_cb;
// PyObject *_py_str_cb;
//void lua_add_num_field (const char *name, double value) {
// assert (name && strlen (name));
// my_lua_checkstack (luaState, 3); PyObject* get_user (tgl_peer_t *P);
// lua_pushstring (luaState, name); PyObject* get_peer (tgl_peer_id_t id, tgl_peer_t *P);
// lua_pushnumber (luaState, value);
// lua_settable (luaState, -3); void py_add_string_field (PyObject* dict, char *name, const char *value) {
//} assert (PyDict_Check(dict));
// assert (name && strlen (name));
//void push_tgl_peer_type (int x) { if (!value || !strlen (value)) { return; }
// switch (x) { PyDict_SetItemString (dict, name, PyString_FromString(value));
// case TGL_PEER_USER: }
// lua_pushstring (luaState, "user");
// break; void py_add_string_field_arr (PyObject* list, int num, const char *value) {
// case TGL_PEER_CHAT: assert(PyList_Check(list));
// lua_pushstring (luaState, "chat"); if (!value || !strlen (value)) { return; }
// break; if(num >= 0)
// case TGL_PEER_ENCR_CHAT: PyList_SetItem (list, num, PyString_FromString (value));
// lua_pushstring (luaState, "encr_chat"); else // Append
// break; PyList_Append (list, PyString_FromString (value));
// default: }
// assert (0);
// } void py_add_num_field (PyObject* dict, const char *name, double value) {
//} assert (PyDict_Check(dict));
// assert (name && strlen (name));
//void push_user (tgl_peer_t *P) { PyDict_SetItemString (dict, name, PyFloat_FromDouble(value));
// my_lua_checkstack (luaState, 4); }
// lua_add_string_field ("first_name", P->user.first_name);
// lua_add_string_field ("last_name", P->user.last_name); PyObject* get_tgl_peer_type (int x) {
// lua_add_string_field ("real_first_name", P->user.real_first_name); PyObject *type;
// lua_add_string_field ("real_last_name", P->user.real_last_name);
// lua_add_string_field ("phone", P->user.phone); switch (x) {
// if (P->user.access_hash) { case TGL_PEER_USER:
// lua_add_num_field ("access_hash", 1); type = PyString_FromString("user");
// } break;
//} case TGL_PEER_CHAT:
// type = PyString_FromString("chat");
//void push_chat (tgl_peer_t *P) { break;
// my_lua_checkstack (luaState, 4); case TGL_PEER_ENCR_CHAT:
// assert (P->chat.title); type = PyString_FromString("encr_chat");
// lua_add_string_field ("title", P->chat.title); break;
// lua_add_num_field ("members_num", P->chat.users_num); default:
// if (P->chat.user_list) { assert (0);
// lua_pushstring (luaState, "members"); }
// lua_newtable (luaState);
// int i; return type;
// for (i = 0; i < P->chat.users_num; i++) { }
// lua_pushnumber (luaState, i);
// tgl_peer_id_t id = TGL_MK_USER (P->chat.user_list[i].user_id); PyObject* get_user (tgl_peer_t *P) {
// push_peer (id, tgl_peer_get (TLS, id)); PyObject *user;
// lua_settable (luaState, -3);
// } user = PyDict_New();
// lua_settable (luaState, -3); if(user == NULL)
// } assert(0); // TODO handle python exception
//}
// py_add_string_field (user, "first_name", P->user.first_name);
//void push_encr_chat (tgl_peer_t *P) { py_add_string_field (user, "last_name", P->user.last_name);
// my_lua_checkstack (luaState, 4); py_add_string_field (user, "real_first_name", P->user.real_first_name);
// lua_pushstring (luaState, "user"); py_add_string_field (user, "real_last_name", P->user.real_last_name);
// push_peer (TGL_MK_USER (P->encr_chat.user_id), tgl_peer_get (TLS, TGL_MK_USER (P->encr_chat.user_id))); py_add_string_field (user, "phone", P->user.phone);
// lua_settable (luaState, -3); if (P->user.access_hash) {
//} py_add_num_field (user, "access_hash", 1);
// }
//void push_update_types (unsigned flags) {
// my_lua_checkstack (luaState, 4); return user;
// lua_newtable (luaState); }
// int cc = 0;
// PyObject* get_chat (tgl_peer_t *P) {
// PyObject *chat, *members;
// if (flags & TGL_UPDATE_CREATED) {
// lua_add_string_field_arr (cc++, "created"); chat = PyDict_New();
// } if(chat == NULL)
// if (flags & TGL_UPDATE_DELETED) { assert(0); // TODO handle python exception
// lua_add_string_field_arr (cc++, "deleted");
// } assert (P->chat.title);
// if (flags & TGL_UPDATE_PHONE) {
// lua_add_string_field_arr (cc++, "phone"); py_add_string_field (chat, "title", P->chat.title);
// } py_add_num_field (chat, "members_num", P->chat.users_num);
// if (flags & TGL_UPDATE_CONTACT) { if (P->chat.user_list) {
// lua_add_string_field_arr (cc++, "contact"); members = PyList_New(P->chat.users_num);
// } if(members == NULL)
// if (flags & TGL_UPDATE_PHOTO) { assert(0); // TODO handle python exception
// lua_add_string_field_arr (cc++, "photo");
// } int i;
// if (flags & TGL_UPDATE_BLOCKED) { for (i = 0; i < P->chat.users_num; i++) {
// lua_add_string_field_arr (cc++, "blocked"); tgl_peer_id_t id = TGL_MK_USER (P->chat.user_list[i].user_id);
// } PyList_SetItem (members, i, get_peer(id, tgl_peer_get (TLS, id)));
// if (flags & TGL_UPDATE_REAL_NAME) { }
// lua_add_string_field_arr (cc++, "real_name"); PyDict_SetItemString (chat, "members", members);
// } }
// if (flags & TGL_UPDATE_NAME) {
// lua_add_string_field_arr (cc++, "name"); return chat;
// } }
// if (flags & TGL_UPDATE_REQUESTED) {
// lua_add_string_field_arr (cc++, "requested"); PyObject* get_encr_chat (tgl_peer_t *P) {
// } PyObject *encr_chat, *user;
// if (flags & TGL_UPDATE_WORKING) {
// lua_add_string_field_arr (cc++, "working"); encr_chat = PyDict_New();
// } if(encr_chat == NULL)
// if (flags & TGL_UPDATE_FLAGS) { assert(0); // TODO handle python exception
// lua_add_string_field_arr (cc++, "flags");
// } user = get_peer (TGL_MK_USER (P->encr_chat.user_id), tgl_peer_get (TLS, TGL_MK_USER (P->encr_chat.user_id)));
// if (flags & TGL_UPDATE_TITLE) { PyDict_SetItemString (encr_chat, "user", user);
// lua_add_string_field_arr (cc++, "title");
// } return encr_chat;
// if (flags & TGL_UPDATE_ADMIN) { }
// lua_add_string_field_arr (cc++, "admin");
// } PyObject* get_update_types (unsigned flags) {
// if (flags & TGL_UPDATE_MEMBERS) { PyObject* types;
// lua_add_string_field_arr (cc++, "members"); types = PyList_New(0);
// } if(types == NULL)
// if (flags & TGL_UPDATE_ACCESS_HASH) { assert(0); // TODO handle python exception
// lua_add_string_field_arr (cc++, "access_hash");
// } if (flags & TGL_UPDATE_CREATED) {
// if (flags & TGL_UPDATE_USERNAME) { py_add_string_field_arr(types, -1, "created");
// lua_add_string_field_arr (cc++, "username"); }
// } if (flags & TGL_UPDATE_DELETED) {
// py_add_string_field_arr(types, -1, "deleted");
//} }
// if (flags & TGL_UPDATE_PHONE) {
//void push_peer (tgl_peer_id_t id, tgl_peer_t *P) { py_add_string_field_arr(types, -1, "phone");
// lua_newtable (luaState); }
// if (flags & TGL_UPDATE_CONTACT) {
// lua_add_num_field ("id", tgl_get_peer_id (id)); py_add_string_field_arr(types, -1, "contact");
// lua_pushstring (luaState, "type"); }
// push_tgl_peer_type (tgl_get_peer_type (id)); if (flags & TGL_UPDATE_PHOTO) {
// lua_settable (luaState, -3); py_add_string_field_arr(types, -1, "photo");
// }
// if (flags & TGL_UPDATE_BLOCKED) {
// if (!P || !(P->flags & FLAG_CREATED)) { py_add_string_field_arr(types, -1, "blocked");
// lua_pushstring (luaState, "print_name"); }
// static char s[100]; if (flags & TGL_UPDATE_REAL_NAME) {
// switch (tgl_get_peer_type (id)) { py_add_string_field_arr(types, -1, "real_name");
// case TGL_PEER_USER: }
// sprintf (s, "user#%d", tgl_get_peer_id (id)); if (flags & TGL_UPDATE_NAME) {
// break; py_add_string_field_arr(types, -1, "name");
// case TGL_PEER_CHAT: }
// sprintf (s, "chat#%d", tgl_get_peer_id (id)); if (flags & TGL_UPDATE_REQUESTED) {
// break; py_add_string_field_arr(types, -1, "requested");
// case TGL_PEER_ENCR_CHAT: }
// sprintf (s, "encr_chat#%d", tgl_get_peer_id (id)); if (flags & TGL_UPDATE_WORKING) {
// break; py_add_string_field_arr(types, -1, "working");
// default: }
// assert (0); if (flags & TGL_UPDATE_FLAGS) {
// } py_add_string_field_arr(types, -1, "flags");
// lua_pushstring (luaState, s); }
// lua_settable (luaState, -3); // flags if (flags & TGL_UPDATE_TITLE) {
// py_add_string_field_arr(types, -1, "title");
// return; }
// } if (flags & TGL_UPDATE_ADMIN) {
// py_add_string_field_arr(types, -1, "admin");
// lua_add_string_field ("print_name", P->print_name); }
// lua_add_num_field ("flags", P->flags); if (flags & TGL_UPDATE_MEMBERS) {
// py_add_string_field_arr(types, -1, "members");
// switch (tgl_get_peer_type (id)) { }
// case TGL_PEER_USER: if (flags & TGL_UPDATE_ACCESS_HASH) {
// push_user (P); py_add_string_field_arr(types, -1, "access_hash");
// break; }
// case TGL_PEER_CHAT: if (flags & TGL_UPDATE_USERNAME) {
// push_chat (P); py_add_string_field_arr(types, -1, "username");
// break; }
// case TGL_PEER_ENCR_CHAT: return types;
// push_encr_chat (P); }
// break;
// default: PyObject* get_peer (tgl_peer_id_t id, tgl_peer_t *P) {
// assert (0); PyObject *peer;
// }
//} peer = PyDict_New();
// if(peer == NULL)
//void push_media (struct tgl_message_media *M) { assert(0); // TODO handle python exception;
// my_lua_checkstack (luaState, 4);
// PyDict_SetItemString (peer, "type", get_tgl_peer_type (tgl_get_peer_type(id)));
// switch (M->type) {
// case tgl_message_media_photo: if (!P || !(P->flags & FLAG_CREATED)) {
// case tgl_message_media_photo_encr: PyObject *name;
// lua_newtable (luaState);
// lua_add_string_field ("type", "photo"); static char s[100];
// break; switch (tgl_get_peer_type (id)) {
// /*case tgl_message_media_video: case TGL_PEER_USER:
// case tgl_message_media_video_encr: sprintf (s, "user#%d", tgl_get_peer_id (id));
// lua_newtable (luaState); break;
// lua_add_string_field ("type", "video"); case TGL_PEER_CHAT:
// break; sprintf (s, "chat#%d", tgl_get_peer_id (id));
// case tgl_message_media_audio: break;
// case tgl_message_media_audio_encr: case TGL_PEER_ENCR_CHAT:
// lua_newtable (luaState); sprintf (s, "encr_chat#%d", tgl_get_peer_id (id));
// lua_add_string_field ("type", "audio"); break;
// break;*/ default:
// case tgl_message_media_document: assert (0);
// case tgl_message_media_document_encr: }
// lua_newtable (luaState);
// lua_add_string_field ("type", "document"); name = PyDict_New();
// break; if(name == NULL)
// case tgl_message_media_unsupported: assert(0); // TODO handle python exception;
// lua_newtable (luaState);
// lua_add_string_field ("type", "unsupported"); PyDict_SetItemString (name, "print_name", PyString_FromString(s));
// break; PyDict_SetItemString (peer, "peer", name);
// case tgl_message_media_geo: } else {
// lua_newtable (luaState); PyObject *peer_obj;
// lua_add_string_field ("type", "geo");
// lua_add_num_field ("longitude", M->geo.longitude); switch (tgl_get_peer_type (id)) {
// lua_add_num_field ("latitude", M->geo.latitude); case TGL_PEER_USER:
// break; peer_obj = get_user (P);
// case tgl_message_media_contact: break;
// lua_newtable (luaState); case TGL_PEER_CHAT:
// lua_add_string_field ("type", "contact"); peer_obj = get_chat (P);
// lua_add_string_field ("phone", M->phone); break;
// lua_add_string_field ("first_name", M->first_name); case TGL_PEER_ENCR_CHAT:
// lua_add_string_field ("last_name", M->last_name); peer_obj = get_encr_chat (P);
// lua_add_num_field ("user_id", M->user_id); break;
// break; default:
// default: assert (0);
// lua_pushstring (luaState, "???"); }
// } PyDict_SetItemString (peer, "peer", peer_obj);
//} }
//
//void push_message (struct tgl_message *M) { return peer;
// assert (M); }
// my_lua_checkstack (luaState, 10);
// lua_newtable (luaState); PyObject* get_media (struct tgl_message_media *M) {
// PyObject *media;
// static char s[30];
// snprintf (s, 30, "%lld", M->id); media = PyDict_New();
// lua_add_string_field ("id", s); if(media == NULL)
// if (!(M->flags & FLAG_CREATED)) { return; } assert(0); // TODO handle python exception
// lua_add_num_field ("flags", M->flags);
// switch (M->type) {
// if (tgl_get_peer_type (M->fwd_from_id)) { case tgl_message_media_photo:
// lua_pushstring (luaState, "fwd_from"); case tgl_message_media_photo_encr:
// push_peer (M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id)); py_add_string_field (media, "type", "photo");
// lua_settable (luaState, -3); // fwd_from break;
// /*case tgl_message_media_video:
// lua_add_num_field ("fwd_date", M->fwd_date); case tgl_message_media_video_encr:
// } lua_newtable (luaState);
// lua_add_string_field ("type", "video");
// lua_pushstring (luaState, "from"); break;
// push_peer (M->from_id, tgl_peer_get (TLS, M->from_id)); case tgl_message_media_audio:
// lua_settable (luaState, -3); case tgl_message_media_audio_encr:
// lua_newtable (luaState);
// lua_pushstring (luaState, "to"); lua_add_string_field ("type", "audio");
// push_peer (M->to_id, tgl_peer_get (TLS, M->to_id)); break;*/
// lua_settable (luaState, -3); case tgl_message_media_document:
// case tgl_message_media_document_encr:
// lua_pushstring (luaState, "out"); py_add_string_field (media, "type", "document");
// lua_pushboolean (luaState, M->out); break;
// lua_settable (luaState, -3); case tgl_message_media_unsupported:
// py_add_string_field (media, "type", "unsupported");
// lua_pushstring (luaState, "unread"); break;
// lua_pushboolean (luaState, M->unread); case tgl_message_media_geo:
// lua_settable (luaState, -3); py_add_string_field (media, "type", "geo");
// py_add_num_field (media, "longitude", M->geo.longitude);
// lua_pushstring (luaState, "date"); py_add_num_field (media, "latitude", M->geo.latitude);
// lua_pushnumber (luaState, M->date); break;
// lua_settable (luaState, -3); case tgl_message_media_contact:
// py_add_string_field (media, "type", "contact");
// lua_pushstring (luaState, "service"); py_add_string_field (media, "phone", M->phone);
// lua_pushboolean (luaState, M->service); py_add_string_field (media, "first_name", M->first_name);
// lua_settable (luaState, -3); py_add_string_field (media, "last_name", M->last_name);
// py_add_num_field (media, "user_id", M->user_id);
// if (!M->service) { break;
// if (M->message_len && M->message) { default:
// lua_pushstring (luaState, "text"); py_add_string_field (media, "type", "unknown");
// lua_pushlstring (luaState, M->message, M->message_len); }
// lua_settable (luaState, -3);
// } return media;
// if (M->media.type && M->media.type != tgl_message_media_none) { }
// lua_pushstring (luaState, "media");
// push_media (&M->media); PyObject* get_message (struct tgl_message *M) {
// lua_settable (luaState, -3); assert (M);
// } PyObject *msg;
// }
//} msg = PyDict_New();
// if(msg == NULL)
assert(0); // TODO handle python exception
static char s[30];
snprintf (s, 30, "%lld", M->id);
py_add_string_field (msg, "id", s);
if (!(M->flags & FLAG_CREATED)) { return msg; }
py_add_num_field (msg, "flags", M->flags);
if (tgl_get_peer_type (M->fwd_from_id)) {
PyDict_SetItemString(msg, "fwd_from", get_peer(M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id)));
py_add_num_field (msg, "fwd_date", M->fwd_date);
}
PyDict_SetItemString(msg, "from", get_peer(M->from_id, tgl_peer_get (TLS, M->from_id)));
PyDict_SetItemString(msg, "to", get_peer(M->to_id, tgl_peer_get (TLS, M->to_id)));
PyDict_SetItemString(msg, "out", (M->out ? Py_True : Py_False));
PyDict_SetItemString(msg, "unread", (M->unread ? Py_True : Py_False));
PyDict_SetItemString(msg, "service", (M->service ? Py_True : Py_False));
PyDict_SetItemString(msg, "date", PyLong_FromLong(M->date)); // TODO put this into PyDate object
if (!M->service) {
if (M->message_len && M->message) {
PyDict_SetItemString(msg, "text", PyString_FromStringAndSize(M->message, M->message_len));
}
if (M->media.type && M->media.type != tgl_message_media_none) {
PyDict_SetItemString(msg, "media", get_media(&M->media));
}
}
return msg;
}
//void lua_binlog_end (void) { //void lua_binlog_end (void) {
// if (!have_file) { return; } // if (!have_file) { return; }
// lua_settop (luaState, 0); // lua_settop (luaState, 0);
@ -384,36 +416,37 @@ void py_our_id (int id) {
} }
void py_new_msg (struct tgl_message *M) { void py_new_msg (struct tgl_message *M) {
// if (!have_file) { return; } if (!have_file) { return; }
// lua_settop (luaState, 0); PyObject *msg;
// //lua_checkstack (luaState, 20); PyObject *arglist, *result;
// my_lua_checkstack (luaState, 20);
// lua_getglobal (luaState, "on_msg_receive"); msg = get_message (M);
// push_message (M);
// assert (lua_gettop (luaState) == 2); arglist = Py_BuildValue("O", msg);
// result = PyEval_CallObject(_py_new_msg, arglist);
// int r = lua_pcall (luaState, 1, 0, 0); Py_DECREF(arglist);
// if (r) {
// logprintf ("lua: %s\n", lua_tostring (luaState, -1)); assert(result && PyString_Check(result)); // TODO handle python exception
// } logprintf ("python: %s\n", PyString_AsString(result));
} }
void py_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) { void py_secret_chat_update (struct tgl_secret_chat *C, unsigned flags) {
// if (!have_file) { return; } if (!have_file) { return; }
// lua_settop (luaState, 0); PyObject *peer, *types;
// //lua_checkstack (luaState, 20); PyObject *arglist, *result;
// my_lua_checkstack (luaState, 20);
// lua_getglobal (luaState, "on_secret_chat_update"); peer = get_peer (C->id, (void *)C);
// push_peer (C->id, (void *)C); types = get_update_types (flags);
// push_update_types (flags);
// assert (lua_gettop (luaState) == 3); arglist = Py_BuildValue("OO", peer, types);
// result = PyEval_CallObject(_py_secret_chat_update, arglist);
// int r = lua_pcall (luaState, 2, 0, 0); Py_DECREF(arglist);
// if (r) {
// logprintf ("lua: %s\n", lua_tostring (luaState, -1)); assert(result && PyString_Check(result)); // TODO handle python exception
// } logprintf ("python: %s\n", PyString_AsString(result));
} }
void py_user_update (struct tgl_user *U, unsigned flags) { void py_user_update (struct tgl_user *U, unsigned flags) {
// if (!have_file) { return; } // if (!have_file) { return; }
// lua_settop (luaState, 0); // lua_settop (luaState, 0);
@ -1429,23 +1462,36 @@ void py_chat_update (struct tgl_chat *C, unsigned flags) {
//} //}
// //
// //
//static void my_python_register (const char *name, lua_CFunction f) { static void my_python_register (PyObject *dict, const char *name, PyObject *f) {
// lua_pushstring(L, name); // Store callables for python functions
// lua_pushcclosure(L, f, 1); f = PyDict_GetItemString(dict, name);
// lua_setglobal(L, name); assert(PyCallable_Check(f)); // TODO handle this
//} }
//
//
void py_init (const char *file) { void py_init (const char *file) {
if (!file) { return; } if (!file) { return; }
have_file = 1; have_file = 1;
PyObject *pName, *pModule; PyObject *pName, *pModule, *pDict;
Py_Initialize(); Py_Initialize();
pName = PyString_FromString(file); pName = PyString_FromString(file);
pModule = PyImport_Import(pName); pModule = PyImport_Import(pName);
pDict = PyModule_GetDict(pModule);
// Store callables for python functions
my_python_register(pDict, "on_binlog_replay_end", _py_binlog_end);
my_python_register(pDict, "on_get_difference_end", _py_diff_end);
my_python_register(pDict, "on_our_id", _py_our_id);
my_python_register(pDict, "on_msg_receive", _py_new_msg);
my_python_register(pDict, "on_secret_chat_update", _py_secret_chat_update);
my_python_register(pDict, "on_user_update", _py_user_update);
my_python_register(pDict, "on_chat_update", _py_chat_update);
// PyObject* err = PyErr_Occurred(); // PyObject* err = PyErr_Occurred();
// if (err != NULL) { // if (err != NULL) {

23
test.py Normal file
View File

@ -0,0 +1,23 @@
def on_binlog_replay_end():
pass
def on_get_difference_end():
pass
def on_our_id():
pass
def on_msg_receive(msg):
return "Got msg!"
def on_secret_chat_update(peer, types):
return "on_secret_chat_update"
def on_user_update():
pass
def on_chat_update():
pass