Self modifying code with Build API

Hi,
Tried out the Build API and implemented agent that updates the devices source code.
Agent will load the devices source code and replace the static “PERMANENT_COUNTER” variable with new value. After modifications device is rebooted to show new value.

So every time you reload the agents url, hardcoded variable will be increment in devices code.

I know, Build API probably wasn’t meant for this kind of stuff :wink:

– Start of agent code –
`
BUILD_API_KEY <- “<CREATE_YOUR_BUILD_API_KEY_FROM_IDE>”;
MODEL_ID <- “<PUT_YOUR_MODELS_ID_HERE>”;

counter <- 1;

function HttpPostWrapper (url, headers, string) {
local request = http.post(url, headers, string);
local response = request.sendsync();
return response;
}

function HttpGetWrapper (url, headers) {
local request = http.get(url, headers);
local response = request.sendsync();
return response;
}

function getLatestCodeRevision( buildApiKey, modelId ){
url <- “https://build.electricimp.com/v4/models/” + modelId + “/revisions”;
headers <- {“Authorization” :"Basic " + http.base64encode(buildApiKey) };

local response = HttpGetWrapper (url, headers);
local data = http.jsondecode( response.body );
return data.revisions[0].version;

}

function getModelsDevices(buildApiKey, modelId){
url <- “https://build.electricimp.com/v4/models/” + modelId;
headers <- {“Authorization” :"Basic " + http.base64encode(buildApiKey) };

local response = HttpGetWrapper (url, headers);
local data = http.jsondecode( response.body );
return data.model.devices;

}

function getDeviceCode( buildApiKey, modelId, revision ){
headers <- {“Authorization” :“Basic " + http.base64encode(buildApiKey) };
url = “https://build.electricimp.com/v4/models/”+ modelId +”/revisions/" + revision;
local response = HttpGetWrapper (url, headers);
local data = http.jsondecode( response.body );
return data.revision.device_code;
}

// Modify code by setting “value” to "variable"
function modifyCodeVariable( code, variable, value ){
local codeArray = split( code, “
”);

local newCode = "";
foreach( line in codeArray ){
    // If the line starts with the variables name, we'll modify it.
    if ( lstrip(line).find(variable) == 0 ){
        local index = line.find(variable);
        local newLine = line.slice(0, index);
        newLine += variable + " <- " + value + ";";
        newCode += newLine + @"

“;
} else {
newCode += line + @”
";
}
}

return newCode;

}

function updateDeviceCode(buildApiKey, deviceCode){
headers <- {“Authorization” :"Basic " + http.base64encode(buildApiKey),
“Content-Type” : “application/json”
}

url <- "https://build.electricimp.com/v4/models/"+ MODEL_ID +"/revisions";
body <- @"{""device_code"": " + http.jsonencode(deviceCode) + @"  }";

local response = HttpPostWrapper (url, headers, body);
if ( response.statuscode == 200) {
    return true;
} else {
    server.log("Code: " + response.statuscode + ". Message: " + response.body);
    return false;
}

}

function requestHandler(request, response)
{
// Get latest revision
local revision = getLatestCodeRevision( BUILD_API_KEY, MODEL_ID );
server.log("Latest code revision is " + revision);

// Load the latest code
local code = getDeviceCode( BUILD_API_KEY, MODEL_ID, revision );

// Modify the code
local newCode = modifyCodeVariable( code, "PERMANENT_COUNTER", counter);
counter++;

// Update the code back to device
local status = updateDeviceCode(BUILD_API_KEY, newCode );
if ( status ){
    response.send(200, "Device code updated. Remember to refresh your IDE to see changes.");
    device.send("reboot", true);
} else {
    response.send(200, "Failed to update code.");
}

}

http.onrequest(requestHandler);

server.log( “Each time you reload this url[” + http.agenturl() + “] devices hardcoded variable will be incremented.”);
`
– End of agent code –

– Start of Device code –
`
// This is an example code in device that is modified by agent
// Agent modifies the “PERMANENT_COUNTER” value.
PERMANENT_COUNTER <- 0;
server.log( "Value of ‘hardcoded’ counter is " + PERMANENT_COUNTER );

function reboot(param){
server.restart();
}
agent.on(“reboot”, reboot);
`
– End of device code –