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

Dependents:   RPC_mbed_client RPC_Wifly_HelloWorld RPC_Ethernet_HelloWorld

MbedJSONRpc.cpp

Committer:
samux
Date:
2012-08-23
Revision:
7:067cb01b491e
Parent:
2:af408b5cae75

File content as of revision 7:067cb01b491e:

#include "MbedJSONRpc.h"

RPC_TYPE MbedJSONRpc::call(char * fn, char * dest, MbedJSONValue& val, MbedJSONValue& resp) {

    char json[150];
    RPC_TYPE t;
    string str = val.serialize();
    int id = rand() % 100;
    MbedJSONValue tmp;


    sprintf(json, (const char *)MSG_CALL, my_id, dest, id, fn, str.c_str());
    webs->send(json);
    t = waitAnswer(tmp, id, json);
    if (t != CALL_OK)
        return t;
    resp = tmp["res"];
    return CALL_OK;
}

RPC_TYPE MbedJSONRpc::waitAnswer(MbedJSONValue& v, int id, char * json) {
    Timer tmr;

    tmr.start();
    while (1) {
        if (tmr.read() > 5.0) {
        #ifdef DEBUG
            printf("timeout\r\n");
        #endif
            return SERVER_NOT_CONNECTED;
        }
        if (webs->read(json)) {
        #ifdef DEBUG
            printf("receive: %s\r\n", json);
        #endif
            parse(v, json);
            return decodeMsg(v, id);
        }
    }
}

int MbedJSONRpc::methodAlreadyRegistered(char * s) {
    for (int i = 0; i < index; i++)
        if (!strcmp(name[i], s))
            return i;
    return -1;
}


int MbedJSONRpc::procAlreadyRegistered(char * s) {
    for (int i = 0; i < index_proc; i++)
        if (!strcmp(name_proc[i], s))
            return i;
    return -1;
}

void MbedJSONRpc::checkMethods(char * dest) {
    char json[150];
    char name[5];
    MbedJSONValue tmp;
    int id = rand() % 100;

    sprintf(json, (const char *)MSG_INFO_METHODS, my_id, dest, id);
    webs->send(json);
    waitAnswer(tmp, id, json);
    printf("methods available on %s: ", dest);
    for (int i = 0; i < tmp.size() - 1; i++) {
        sprintf(name, "fn%d", i);
        printf("%s%c ", tmp[name].get<string>().c_str(), (i == tmp.size() - 2) ? ' ' : ',');
    }
    printf("\r\n");
}

RPC_TYPE MbedJSONRpc::decodeMsg(MbedJSONValue& v, int id) {

    if (v.hasMember("id_msg"))
        if (v["id_msg"].get<int>() != -1 && id != v["id_msg"].get<int>()) {
        #ifdef DEBUG
            printf("bad id: %d\r\n",v["id_msg"].get<int>() );
        #endif
            return ERR_ID;
        }

    if (v.hasMember("msg")) {
        std::string s = v["msg"].get<std::string>();
        if (!strcmp(s.c_str(), "RESULT")) {
            return CALL_OK;
        }
        if (!strcmp(s.c_str(), "REGISTER_OK")) {
            return REGISTER_OK;
        }
    }

    //there is an error
    if (v.hasMember("cause")) {
        std::string s = v["cause"].get<std::string>();
        if (!strcmp(s.c_str(), "JSON_PARSE_ERROR"))
            return JSON_PARSE_ERROR;
        if (!strcmp(s.c_str(), "JSON_RPC_ERROR"))
            return RPC_PARSE_ERROR;
        else if (!strcmp(s.c_str(), "METHOD_NOT_FOUND"))
            return PROC_NOT_FOUND;
        else if (!strcmp(s.c_str(), "CLIENT_NOT_CONNECTED"))
            return CLIENT_NOT_CONNECTED;
    }
    return RPC_PARSE_ERROR;

}


RPC_TYPE MbedJSONRpc::registerMethod(const char * public_name, void (*fn)(MbedJSONValue& val, MbedJSONValue& res) ) {
    char json[100];
    int id = rand() % 100;
    MbedJSONValue tmp;
    RPC_TYPE t;

    sprintf(json, (const char *)MSG_REGISTER, my_id, id, public_name);
    webs->send(json);
    t = waitAnswer(tmp, id, json);
    if (t != REGISTER_OK)
        return t;
    if( index_proc == NB_METH )
        index_proc = NB_METH - 1;
    proc[index_proc] = fn;
    name_proc[index_proc++] = public_name;
    return REGISTER_OK;
}


void MbedJSONRpc::work() {
    char json_recv[150];
    DigitalOut led4(LED4);
    MbedJSONValue v, r;
    int i = -1;
    while (1) {
        wait(0.2);
        if (webs->read(json_recv)) {
            parse(v, json_recv);
            if (v.hasMember("method") && v.hasMember("from") && v.hasMember("id_msg") && v.hasMember("params") && v.hasMember("msg") && !strcmp(v["msg"].get<std::string>().c_str(), "CALL")) {
            
                string s = v["method"].get<std::string>();
                
                if ((i = methodAlreadyRegistered((char *)s.c_str())) != -1) {
                
                    obj[i]->execute(v["params"], r);
                    sprintf(json_recv, (const char *)MSG_RESULT, my_id,
                            v["from"].get<std::string>().c_str(), v["id_msg"].get<int>(), r.serialize().c_str());
                    webs->send(json_recv);
                    
                } else if ((i = procAlreadyRegistered((char *)s.c_str())) != -1) {
                
                    proc[i](v["params"], r);
                    sprintf(json_recv, (const char *)MSG_RESULT, my_id,
                            v["from"].get<std::string>().c_str(), v["id_msg"].get<int>(), r.serialize().c_str());
                    webs->send(json_recv);
                    
                }
            }

        }
        //show that we are alive
        led4 = !led4;
    }
}