Remote Procedure Call (RPC) over Websockets (uses MbedJSONValue)
Dependents: RPC_mbed_client RPC_Wifly_HelloWorld RPC_Ethernet_HelloWorld
MbedJSONRpc.h
00001 /** 00002 * @author Samuel Mokrani 00003 * 00004 * @section LICENSE 00005 * 00006 * Copyright (c) 2011 mbed 00007 * 00008 * Permission is hereby granted, free of charge, to any person obtaining a copy 00009 * of this software and associated documentation files (the "Software"), to deal 00010 * in the Software without restriction, including without limitation the rights 00011 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00012 * copies of the Software, and to permit persons to whom the Software is 00013 * furnished to do so, subject to the following conditions: 00014 * 00015 * The above copyright notice and this permission notice shall be included in 00016 * all copies or substantial portions of the Software. 00017 * 00018 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00019 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00020 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00021 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00022 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00023 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00024 * THE SOFTWARE. 00025 * 00026 * @section DESCRIPTION 00027 * Main part of MbedJSONRpc: you can register methods or procedures, call a registered method or procedure 00028 * on a client over a websocket communication, see all methods available on a certain client, listen for 00029 * CALL incoming messages to execute a method or procedure. 00030 * 00031 */ 00032 00033 00034 #ifndef _MbedJSONRPC_H_ 00035 #define _MbedJSONRPC_H_ 00036 00037 #include "Websocket.h" 00038 #include "mbed.h" 00039 #include "MbedJSONValue.h" 00040 #include <string> 00041 00042 #define NB_METH 30 00043 00044 #define MSG_CALL "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"CALL\",\"id_msg\": %d,\"method\": \"%s\",\"params\":%s}" 00045 /**< Message skeleton which will be use for a call */ 00046 #define MSG_RESULT "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"RESULT\",\"id_msg\": %d,\"res\":%s}" 00047 /**< Message skeleton which will be use for a result */ 00048 #define MSG_REGISTER "{\"from\": \"%s\",\"to\": \"gateway\",\"msg\": \"REGISTER\",\"id_msg\": %d,\"fn\":\"%s\"}" 00049 /**< Message skeleton which will be use for register a method or a procedure */ 00050 #define MSG_INFO_METHODS "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"INFO_METHODS\",\"id_msg\": %d}" 00051 /**< Message skeleton which will be send to see all methods available of a certain client */ 00052 00053 00054 /** 00055 * \enum RPC_TYPE 00056 * \brief Type of an RPC transaction 00057 */ 00058 enum RPC_TYPE { 00059 JSON_PARSE_ERROR, /*!< Json parse error */ 00060 RPC_PARSE_ERROR, /*!< rpc parse error (the message doesn't contain good identifiers in a TypeObject MbedJSONValue)*/ 00061 PROC_NOT_FOUND, /*!< The user wants to call an inexisting method or procedure */ 00062 CLIENT_NOT_CONNECTED, /*!< The user wants to call a method or procedure on a client not connected (no response from the client within 3s) */ 00063 SERVER_NOT_CONNECTED, /*!< No response from the server within 5s */ 00064 ERR_ID, /*!< Each messages have an id, if the id of the answer doesn't match with the id of the request, there is an id error */ 00065 CALL_OK, /*!< A call has been successfully executed */ 00066 REGISTER_OK /*!< A request to register a method or procedure is successful */ 00067 }; 00068 00069 00070 00071 class ObjBase { 00072 public: 00073 virtual void execute(MbedJSONValue& val, MbedJSONValue& res) = 0; 00074 }; 00075 00076 template <class T> 00077 class Obj : public ObjBase { 00078 public: 00079 00080 Obj(T * ptr, void (T::*fn_ptr)(MbedJSONValue& , MbedJSONValue& )) { 00081 obj_ptr = ptr; 00082 fn = fn_ptr; 00083 }; 00084 00085 virtual void execute(MbedJSONValue& val, MbedJSONValue& res) { 00086 ((*obj_ptr).*fn)(val, res); 00087 } 00088 00089 //obj 00090 T * obj_ptr; 00091 00092 //method 00093 void (T::*fn)(MbedJSONValue& , MbedJSONValue& ); 00094 00095 }; 00096 00097 00098 /** MbedJSONRpc class 00099 * 00100 */ 00101 class MbedJSONRpc { 00102 public: 00103 00104 /** 00105 * Constructor 00106 * 00107 * @param id Name of the client on the network 00108 * @param ws All communication between clients will be established over this websocket 00109 */ 00110 MbedJSONRpc(Websocket * webs) : webs(webs), index(0), index_proc(0) { 00111 std::string path = webs->getPath(); 00112 std::string token = "/"; 00113 size_t found; 00114 found = path.find(token); 00115 if (found != std::string::npos) 00116 found = path.find(token, found + 1); 00117 if (found != std::string::npos) 00118 path = path.substr(found + 1, std::string::npos); 00119 strcpy(my_id, path.c_str()); 00120 }; 00121 00122 /** 00123 * Register a method of an object 00124 * 00125 * @param public_name the method will be seen and called by this name 00126 * @param obj_ptr a pointeur on the object which contains the method to register 00127 * @param fn the method to register (this method must have this signature: void fn(MbedJSONValue& val, MbedJSONValue& res) 00128 * @return if REGISTER_OK, the method is registered, otherwise, there is an error 00129 * 00130 */ 00131 template<typename T> RPC_TYPE registerMethod(const char * public_name, T * obj_ptr, void (T::*fn)(MbedJSONValue& val, MbedJSONValue& res)) { 00132 char json[100]; 00133 RPC_TYPE t; 00134 Timer tmr; 00135 int id = rand() % 100; 00136 MbedJSONValue tmp; 00137 00138 sprintf(json, (const char *)MSG_REGISTER, my_id, id, public_name); 00139 webs->send(json); 00140 tmr.start(); 00141 t = waitAnswer(tmp, id, json); 00142 if (t != REGISTER_OK) 00143 return t; 00144 if( index == NB_METH ) 00145 index = NB_METH - 1; 00146 obj[index] = new Obj<T>(obj_ptr, fn); 00147 name[index++] = public_name; 00148 return REGISTER_OK; 00149 } 00150 00151 00152 /** 00153 * Register a procedure 00154 * 00155 * @param public_name the method will be seen and called by this name 00156 * @param fn the procedure to register (this procedure must have this signature: void fn(MbedJSONValue& val, MbedJSONValue& res) 00157 * @return if REGISTER_OK, the procedure is registered, otherwise, there is an error 00158 * 00159 */ 00160 RPC_TYPE registerMethod(const char * public_name, void (*fn)(MbedJSONValue& val, MbedJSONValue& res) ); 00161 00162 00163 /** 00164 * Call a method or procedure on a client 00165 * 00166 * @param fn name of the method or procedure to be called 00167 * @param dest name of the client where will be executed the method or procedure 00168 * @param val Input parameters of the method or procedure "fn" 00169 * @param resp Once the method or procedure executed, the result will be stored in the "resp" variable. 00170 * @return If CALL_OK, the method has been executed and you can access the result with the "resp" variable. 00171 * If CLIENT_NOT_CONNECTED, means that the client hasn't answered within 3s. 00172 * If SERVER_NOT_CONNECTED, means that the server hasn't answered within 5s. 00173 * Refer to the RPC_TYPE description 00174 * 00175 */ 00176 RPC_TYPE call(char * fn, char * dest, MbedJSONValue& val, MbedJSONValue& resp); 00177 00178 00179 /** 00180 * Listen for CALL requests. 00181 * Warning: infinite loop 00182 */ 00183 void work(); 00184 00185 /** 00186 * Print by the usb serial port all methods or procedure available on "dest" client 00187 */ 00188 void checkMethods(char * dest); 00189 00190 private: 00191 00192 typedef void (*FNPTR)(MbedJSONValue& , MbedJSONValue& ); 00193 00194 int methodAlreadyRegistered(char *); 00195 int procAlreadyRegistered(char *); 00196 RPC_TYPE decodeMsg(MbedJSONValue& , int); 00197 RPC_TYPE waitAnswer(MbedJSONValue& , int, char *); 00198 00199 Websocket * webs; 00200 00201 ObjBase * obj[NB_METH]; 00202 const char * name[NB_METH]; 00203 int index; 00204 00205 FNPTR proc[NB_METH]; 00206 const char * name_proc[NB_METH]; 00207 int index_proc; 00208 00209 00210 char my_id[20]; 00211 00212 }; 00213 00214 00215 inline void printType(RPC_TYPE t) 00216 { 00217 switch(t) 00218 { 00219 case JSON_PARSE_ERROR: printf("json parse error\r\n"); break; 00220 case RPC_PARSE_ERROR: printf("rpc parse error\r\n"); break; 00221 case PROC_NOT_FOUND: printf("proc or method not found\r\n"); break; 00222 case CLIENT_NOT_CONNECTED: printf("client not connected\r\n"); break; 00223 case SERVER_NOT_CONNECTED: printf("server not connected\r\n"); break; 00224 case ERR_ID: printf("id error\r\n"); break; 00225 case CALL_OK: printf("call ok\r\n"); break; 00226 case REGISTER_OK: printf("register ok\r\n"); break; 00227 } 00228 } 00229 00230 #endif
Generated on Wed Jul 20 2022 02:14:25 by
