Remote Procedure Call (RPC) over Websockets (uses MbedJSONValue)

Dependents:   RPC_mbed_client RPC_Wifly_HelloWorld RPC_Ethernet_HelloWorld

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?

UserRevisionLine numberNew 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