Remote Procedure Call (RPC) over Websockets (uses MbedJSONValue)
Dependents: RPC_mbed_client RPC_Wifly_HelloWorld RPC_Ethernet_HelloWorld
MbedJSONRpc.h@7:067cb01b491e, 2012-08-23 (annotated)
- Committer:
- samux
- Date:
- Thu Aug 23 14:23:37 2012 +0000
- Revision:
- 7:067cb01b491e
- Parent:
- 6:0ec91dd0e80e
update with new websocket client
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
samux | 0:a53d1c86196c | 1 | /** |
samux | 0:a53d1c86196c | 2 | * @author Samuel Mokrani |
samux | 0:a53d1c86196c | 3 | * |
samux | 0:a53d1c86196c | 4 | * @section LICENSE |
samux | 0:a53d1c86196c | 5 | * |
samux | 0:a53d1c86196c | 6 | * Copyright (c) 2011 mbed |
samux | 0:a53d1c86196c | 7 | * |
samux | 0:a53d1c86196c | 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
samux | 0:a53d1c86196c | 9 | * of this software and associated documentation files (the "Software"), to deal |
samux | 0:a53d1c86196c | 10 | * in the Software without restriction, including without limitation the rights |
samux | 0:a53d1c86196c | 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
samux | 0:a53d1c86196c | 12 | * copies of the Software, and to permit persons to whom the Software is |
samux | 0:a53d1c86196c | 13 | * furnished to do so, subject to the following conditions: |
samux | 0:a53d1c86196c | 14 | * |
samux | 0:a53d1c86196c | 15 | * The above copyright notice and this permission notice shall be included in |
samux | 0:a53d1c86196c | 16 | * all copies or substantial portions of the Software. |
samux | 0:a53d1c86196c | 17 | * |
samux | 0:a53d1c86196c | 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
samux | 0:a53d1c86196c | 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
samux | 0:a53d1c86196c | 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
samux | 0:a53d1c86196c | 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
samux | 0:a53d1c86196c | 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
samux | 0:a53d1c86196c | 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
samux | 0:a53d1c86196c | 24 | * THE SOFTWARE. |
samux | 0:a53d1c86196c | 25 | * |
samux | 0:a53d1c86196c | 26 | * @section DESCRIPTION |
samux | 0:a53d1c86196c | 27 | * Main part of MbedJSONRpc: you can register methods or procedures, call a registered method or procedure |
samux | 0:a53d1c86196c | 28 | * on a client over a websocket communication, see all methods available on a certain client, listen for |
samux | 0:a53d1c86196c | 29 | * CALL incoming messages to execute a method or procedure. |
samux | 0:a53d1c86196c | 30 | * |
samux | 0:a53d1c86196c | 31 | */ |
samux | 0:a53d1c86196c | 32 | |
samux | 0:a53d1c86196c | 33 | |
samux | 0:a53d1c86196c | 34 | #ifndef _MbedJSONRPC_H_ |
samux | 0:a53d1c86196c | 35 | #define _MbedJSONRPC_H_ |
samux | 0:a53d1c86196c | 36 | |
samux | 0:a53d1c86196c | 37 | #include "Websocket.h" |
samux | 0:a53d1c86196c | 38 | #include "mbed.h" |
samux | 2:af408b5cae75 | 39 | #include "MbedJSONValue.h" |
samux | 0:a53d1c86196c | 40 | #include <string> |
samux | 0:a53d1c86196c | 41 | |
samux | 0:a53d1c86196c | 42 | #define NB_METH 30 |
samux | 0:a53d1c86196c | 43 | |
samux | 0:a53d1c86196c | 44 | #define MSG_CALL "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"CALL\",\"id_msg\": %d,\"method\": \"%s\",\"params\":%s}" |
samux | 0:a53d1c86196c | 45 | /**< Message skeleton which will be use for a call */ |
samux | 0:a53d1c86196c | 46 | #define MSG_RESULT "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"RESULT\",\"id_msg\": %d,\"res\":%s}" |
samux | 0:a53d1c86196c | 47 | /**< Message skeleton which will be use for a result */ |
samux | 0:a53d1c86196c | 48 | #define MSG_REGISTER "{\"from\": \"%s\",\"to\": \"gateway\",\"msg\": \"REGISTER\",\"id_msg\": %d,\"fn\":\"%s\"}" |
samux | 0:a53d1c86196c | 49 | /**< Message skeleton which will be use for register a method or a procedure */ |
samux | 0:a53d1c86196c | 50 | #define MSG_INFO_METHODS "{\"from\": \"%s\",\"to\": \"%s\",\"msg\": \"INFO_METHODS\",\"id_msg\": %d}" |
samux | 0:a53d1c86196c | 51 | /**< Message skeleton which will be send to see all methods available of a certain client */ |
samux | 0:a53d1c86196c | 52 | |
samux | 0:a53d1c86196c | 53 | |
samux | 0:a53d1c86196c | 54 | /** |
samux | 0:a53d1c86196c | 55 | * \enum RPC_TYPE |
samux | 0:a53d1c86196c | 56 | * \brief Type of an RPC transaction |
samux | 0:a53d1c86196c | 57 | */ |
samux | 0:a53d1c86196c | 58 | enum RPC_TYPE { |
samux | 0:a53d1c86196c | 59 | JSON_PARSE_ERROR, /*!< Json parse error */ |
samux | 2:af408b5cae75 | 60 | RPC_PARSE_ERROR, /*!< rpc parse error (the message doesn't contain good identifiers in a TypeObject MbedJSONValue)*/ |
samux | 0:a53d1c86196c | 61 | PROC_NOT_FOUND, /*!< The user wants to call an inexisting method or procedure */ |
samux | 0:a53d1c86196c | 62 | CLIENT_NOT_CONNECTED, /*!< The user wants to call a method or procedure on a client not connected (no response from the client within 3s) */ |
samux | 0:a53d1c86196c | 63 | SERVER_NOT_CONNECTED, /*!< No response from the server within 5s */ |
samux | 0:a53d1c86196c | 64 | 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 */ |
samux | 0:a53d1c86196c | 65 | CALL_OK, /*!< A call has been successfully executed */ |
samux | 0:a53d1c86196c | 66 | REGISTER_OK /*!< A request to register a method or procedure is successful */ |
samux | 0:a53d1c86196c | 67 | }; |
samux | 0:a53d1c86196c | 68 | |
samux | 0:a53d1c86196c | 69 | |
samux | 0:a53d1c86196c | 70 | |
samux | 0:a53d1c86196c | 71 | class ObjBase { |
samux | 0:a53d1c86196c | 72 | public: |
samux | 2:af408b5cae75 | 73 | virtual void execute(MbedJSONValue& val, MbedJSONValue& res) = 0; |
samux | 0:a53d1c86196c | 74 | }; |
samux | 0:a53d1c86196c | 75 | |
samux | 0:a53d1c86196c | 76 | template <class T> |
samux | 0:a53d1c86196c | 77 | class Obj : public ObjBase { |
samux | 0:a53d1c86196c | 78 | public: |
samux | 0:a53d1c86196c | 79 | |
samux | 2:af408b5cae75 | 80 | Obj(T * ptr, void (T::*fn_ptr)(MbedJSONValue& , MbedJSONValue& )) { |
samux | 0:a53d1c86196c | 81 | obj_ptr = ptr; |
samux | 0:a53d1c86196c | 82 | fn = fn_ptr; |
samux | 0:a53d1c86196c | 83 | }; |
samux | 0:a53d1c86196c | 84 | |
samux | 2:af408b5cae75 | 85 | virtual void execute(MbedJSONValue& val, MbedJSONValue& res) { |
samux | 0:a53d1c86196c | 86 | ((*obj_ptr).*fn)(val, res); |
samux | 0:a53d1c86196c | 87 | } |
samux | 0:a53d1c86196c | 88 | |
samux | 0:a53d1c86196c | 89 | //obj |
samux | 0:a53d1c86196c | 90 | T * obj_ptr; |
samux | 0:a53d1c86196c | 91 | |
samux | 0:a53d1c86196c | 92 | //method |
samux | 2:af408b5cae75 | 93 | void (T::*fn)(MbedJSONValue& , MbedJSONValue& ); |
samux | 0:a53d1c86196c | 94 | |
samux | 0:a53d1c86196c | 95 | }; |
samux | 0:a53d1c86196c | 96 | |
samux | 0:a53d1c86196c | 97 | |
samux | 0:a53d1c86196c | 98 | /** MbedJSONRpc class |
samux | 0:a53d1c86196c | 99 | * |
samux | 0:a53d1c86196c | 100 | */ |
samux | 0:a53d1c86196c | 101 | class MbedJSONRpc { |
samux | 0:a53d1c86196c | 102 | public: |
samux | 0:a53d1c86196c | 103 | |
samux | 0:a53d1c86196c | 104 | /** |
samux | 0:a53d1c86196c | 105 | * Constructor |
samux | 0:a53d1c86196c | 106 | * |
samux | 0:a53d1c86196c | 107 | * @param id Name of the client on the network |
samux | 0:a53d1c86196c | 108 | * @param ws All communication between clients will be established over this websocket |
samux | 0:a53d1c86196c | 109 | */ |
samux | 0:a53d1c86196c | 110 | MbedJSONRpc(Websocket * webs) : webs(webs), index(0), index_proc(0) { |
samux | 0:a53d1c86196c | 111 | std::string path = webs->getPath(); |
samux | 0:a53d1c86196c | 112 | std::string token = "/"; |
samux | 0:a53d1c86196c | 113 | size_t found; |
samux | 6:0ec91dd0e80e | 114 | found = path.find(token); |
samux | 6:0ec91dd0e80e | 115 | if (found != std::string::npos) |
samux | 6:0ec91dd0e80e | 116 | found = path.find(token, found + 1); |
samux | 0:a53d1c86196c | 117 | if (found != std::string::npos) |
samux | 0:a53d1c86196c | 118 | path = path.substr(found + 1, std::string::npos); |
samux | 0:a53d1c86196c | 119 | strcpy(my_id, path.c_str()); |
samux | 0:a53d1c86196c | 120 | }; |
samux | 0:a53d1c86196c | 121 | |
samux | 0:a53d1c86196c | 122 | /** |
samux | 0:a53d1c86196c | 123 | * Register a method of an object |
samux | 0:a53d1c86196c | 124 | * |
samux | 0:a53d1c86196c | 125 | * @param public_name the method will be seen and called by this name |
samux | 0:a53d1c86196c | 126 | * @param obj_ptr a pointeur on the object which contains the method to register |
samux | 2:af408b5cae75 | 127 | * @param fn the method to register (this method must have this signature: void fn(MbedJSONValue& val, MbedJSONValue& res) |
samux | 0:a53d1c86196c | 128 | * @return if REGISTER_OK, the method is registered, otherwise, there is an error |
samux | 0:a53d1c86196c | 129 | * |
samux | 0:a53d1c86196c | 130 | */ |
samux | 2:af408b5cae75 | 131 | template<typename T> RPC_TYPE registerMethod(const char * public_name, T * obj_ptr, void (T::*fn)(MbedJSONValue& val, MbedJSONValue& res)) { |
samux | 0:a53d1c86196c | 132 | char json[100]; |
samux | 0:a53d1c86196c | 133 | RPC_TYPE t; |
samux | 0:a53d1c86196c | 134 | Timer tmr; |
samux | 0:a53d1c86196c | 135 | int id = rand() % 100; |
samux | 2:af408b5cae75 | 136 | MbedJSONValue tmp; |
samux | 0:a53d1c86196c | 137 | |
samux | 0:a53d1c86196c | 138 | sprintf(json, (const char *)MSG_REGISTER, my_id, id, public_name); |
samux | 7:067cb01b491e | 139 | webs->send(json); |
samux | 0:a53d1c86196c | 140 | tmr.start(); |
samux | 0:a53d1c86196c | 141 | t = waitAnswer(tmp, id, json); |
samux | 0:a53d1c86196c | 142 | if (t != REGISTER_OK) |
samux | 0:a53d1c86196c | 143 | return t; |
samux | 0:a53d1c86196c | 144 | if( index == NB_METH ) |
samux | 0:a53d1c86196c | 145 | index = NB_METH - 1; |
samux | 0:a53d1c86196c | 146 | obj[index] = new Obj<T>(obj_ptr, fn); |
samux | 0:a53d1c86196c | 147 | name[index++] = public_name; |
samux | 0:a53d1c86196c | 148 | return REGISTER_OK; |
samux | 0:a53d1c86196c | 149 | } |
samux | 0:a53d1c86196c | 150 | |
samux | 0:a53d1c86196c | 151 | |
samux | 0:a53d1c86196c | 152 | /** |
samux | 0:a53d1c86196c | 153 | * Register a procedure |
samux | 0:a53d1c86196c | 154 | * |
samux | 0:a53d1c86196c | 155 | * @param public_name the method will be seen and called by this name |
samux | 2:af408b5cae75 | 156 | * @param fn the procedure to register (this procedure must have this signature: void fn(MbedJSONValue& val, MbedJSONValue& res) |
samux | 0:a53d1c86196c | 157 | * @return if REGISTER_OK, the procedure is registered, otherwise, there is an error |
samux | 0:a53d1c86196c | 158 | * |
samux | 0:a53d1c86196c | 159 | */ |
samux | 2:af408b5cae75 | 160 | RPC_TYPE registerMethod(const char * public_name, void (*fn)(MbedJSONValue& val, MbedJSONValue& res) ); |
samux | 0:a53d1c86196c | 161 | |
samux | 0:a53d1c86196c | 162 | |
samux | 0:a53d1c86196c | 163 | /** |
samux | 0:a53d1c86196c | 164 | * Call a method or procedure on a client |
samux | 0:a53d1c86196c | 165 | * |
samux | 0:a53d1c86196c | 166 | * @param fn name of the method or procedure to be called |
samux | 0:a53d1c86196c | 167 | * @param dest name of the client where will be executed the method or procedure |
samux | 0:a53d1c86196c | 168 | * @param val Input parameters of the method or procedure "fn" |
samux | 3:4a3bc3a2314f | 169 | * @param resp Once the method or procedure executed, the result will be stored in the "resp" variable. |
samux | 0:a53d1c86196c | 170 | * @return If CALL_OK, the method has been executed and you can access the result with the "resp" variable. |
samux | 0:a53d1c86196c | 171 | * If CLIENT_NOT_CONNECTED, means that the client hasn't answered within 3s. |
samux | 0:a53d1c86196c | 172 | * If SERVER_NOT_CONNECTED, means that the server hasn't answered within 5s. |
samux | 0:a53d1c86196c | 173 | * Refer to the RPC_TYPE description |
samux | 0:a53d1c86196c | 174 | * |
samux | 0:a53d1c86196c | 175 | */ |
samux | 2:af408b5cae75 | 176 | RPC_TYPE call(char * fn, char * dest, MbedJSONValue& val, MbedJSONValue& resp); |
samux | 0:a53d1c86196c | 177 | |
samux | 0:a53d1c86196c | 178 | |
samux | 0:a53d1c86196c | 179 | /** |
samux | 3:4a3bc3a2314f | 180 | * Listen for CALL requests. |
samux | 0:a53d1c86196c | 181 | * Warning: infinite loop |
samux | 0:a53d1c86196c | 182 | */ |
samux | 0:a53d1c86196c | 183 | void work(); |
samux | 0:a53d1c86196c | 184 | |
samux | 0:a53d1c86196c | 185 | /** |
samux | 0:a53d1c86196c | 186 | * Print by the usb serial port all methods or procedure available on "dest" client |
samux | 0:a53d1c86196c | 187 | */ |
samux | 0:a53d1c86196c | 188 | void checkMethods(char * dest); |
samux | 0:a53d1c86196c | 189 | |
samux | 0:a53d1c86196c | 190 | private: |
samux | 0:a53d1c86196c | 191 | |
samux | 2:af408b5cae75 | 192 | typedef void (*FNPTR)(MbedJSONValue& , MbedJSONValue& ); |
samux | 0:a53d1c86196c | 193 | |
samux | 0:a53d1c86196c | 194 | int methodAlreadyRegistered(char *); |
samux | 0:a53d1c86196c | 195 | int procAlreadyRegistered(char *); |
samux | 2:af408b5cae75 | 196 | RPC_TYPE decodeMsg(MbedJSONValue& , int); |
samux | 2:af408b5cae75 | 197 | RPC_TYPE waitAnswer(MbedJSONValue& , int, char *); |
samux | 0:a53d1c86196c | 198 | |
samux | 0:a53d1c86196c | 199 | Websocket * webs; |
samux | 0:a53d1c86196c | 200 | |
samux | 0:a53d1c86196c | 201 | ObjBase * obj[NB_METH]; |
samux | 0:a53d1c86196c | 202 | const char * name[NB_METH]; |
samux | 0:a53d1c86196c | 203 | int index; |
samux | 0:a53d1c86196c | 204 | |
samux | 0:a53d1c86196c | 205 | FNPTR proc[NB_METH]; |
samux | 0:a53d1c86196c | 206 | const char * name_proc[NB_METH]; |
samux | 0:a53d1c86196c | 207 | int index_proc; |
samux | 0:a53d1c86196c | 208 | |
samux | 0:a53d1c86196c | 209 | |
samux | 0:a53d1c86196c | 210 | char my_id[20]; |
samux | 0:a53d1c86196c | 211 | |
samux | 0:a53d1c86196c | 212 | }; |
samux | 0:a53d1c86196c | 213 | |
samux | 0:a53d1c86196c | 214 | |
samux | 0:a53d1c86196c | 215 | inline void printType(RPC_TYPE t) |
samux | 0:a53d1c86196c | 216 | { |
samux | 0:a53d1c86196c | 217 | switch(t) |
samux | 0:a53d1c86196c | 218 | { |
samux | 0:a53d1c86196c | 219 | case JSON_PARSE_ERROR: printf("json parse error\r\n"); break; |
samux | 0:a53d1c86196c | 220 | case RPC_PARSE_ERROR: printf("rpc parse error\r\n"); break; |
samux | 0:a53d1c86196c | 221 | case PROC_NOT_FOUND: printf("proc or method not found\r\n"); break; |
samux | 0:a53d1c86196c | 222 | case CLIENT_NOT_CONNECTED: printf("client not connected\r\n"); break; |
samux | 0:a53d1c86196c | 223 | case SERVER_NOT_CONNECTED: printf("server not connected\r\n"); break; |
samux | 0:a53d1c86196c | 224 | case ERR_ID: printf("id error\r\n"); break; |
samux | 0:a53d1c86196c | 225 | case CALL_OK: printf("call ok\r\n"); break; |
samux | 0:a53d1c86196c | 226 | case REGISTER_OK: printf("register ok\r\n"); break; |
samux | 0:a53d1c86196c | 227 | } |
samux | 0:a53d1c86196c | 228 | } |
samux | 0:a53d1c86196c | 229 | |
samux | 0:a53d1c86196c | 230 | #endif |