EVP Agent SDK¶
Note
Embedding API interfaces
are defined in include/evp/agent.h
.
Although this project provides a stand-alone
EVP Agent executable evp-agent
,
it can be embedded in a user application with
EVP Agent SDK library libevp-agent
.
Runtime¶
Embedding the agent in user application requires the following, as a minimum:
Initialize an agent instance with
evp_agent_setup()
, which returns a instance of the agent context that is then required by allevp_agent_*()
functions.Startup the agent with
evp_agent_start()
.Call
evp_agent_loop()
within a loop that the user may break as they require or when the function returns an error. If previously connected see #3.Stop the agent with
evp_agent_stop()
.Free resources with
evp_agent_free()
.Then the application can safely exit.
int
main(int argc, char *argv[])
{
struct evp_agent_context *agent = evp_agent_setup(argv[0]);
int ret = evp_agent_start(agent);
if (ret)
goto release;
while (ret == 0) {
ret = evp_agent_loop(agent);
}
evp_agent_stop(agent);
release:
evp_agent_free(agent);
return 0;
}
-
struct evp_agent_context¶
Agent context object.
This contains the runtime data for the instance of the running agent.
-
struct evp_agent_context *evp_agent_setup(const char *progname)¶
Initialize an agent instance context object.
This must be called to create an agent context to pass to any
evp_agent_*()
functions that requireevp_agent_context
as parameter.It takes a c string as parameter to set the program name to be printed in error basic log functions
xerr()
andxerrx()
.The agent Status is expected to remain
EVP_AGENT_STATUS_INIT
at this stage.- Parameters:
progname – Program name
- Returns:
A
evp_agent_context
object pointer.- Errors:
The function guaranties to return a valid allocated pointer, or abort if object memory allocation failed.
Example:
int main(int argc, char *argv[]) { struct evp_agent_context *ctxt = evp_agent_setup(argv[0]); ... }
-
int evp_agent_start(struct evp_agent_context *ctxt)¶
Start the agent.
Runs all initialization procedures to start up the agent.
The agent
evp_agent_status
is expected to pass toEVP_AGENT_STATUS_READY
when startup is complete.- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
Always return
0
.- Errors:
This function may abort the program if TLS cannot be initialised or for other internal critical failure reasons.
-
int evp_agent_loop(struct evp_agent_context *ctxt)¶
This is the agent runtime routine to keep calling in an infinite loop.
Note
This is expected to block until agent events are emitted for processing.
It is therefore necessary to keep this call in the loop without any other blocking or time consuming calls, to avoid any unwanted hangs. or delays.
It is expected to handle the following status transitions:
EVP_AGENT_STATUS_CONNECTING
toEVP_AGENT_STATUS_CONNECTED
when agent becomes connected to the hub.EVP_AGENT_STATUS_CONNECTED
toEVP_AGENT_STATUS_CONNECTING
when agent gets disconnected from the hub and is re-establishing connection.EVP_AGENT_STATUS_DISCONNECTING
toEVP_AGENT_STATUS_DISCONNECTED
when agent disconnection is complete after being requested to disconnect from hub.
Warning
If routine is called after a successful stop (
evp_agent_stop()
) the function will return0
and no events will be processed.- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
Returns
0
in mominal case or non-zero if an error occurred.- Errors:
If the agent has not been started with the call to
evp_agent_start()
(EVP_AGENT_STATUS_INIT
), the function will return-1
and not process any event.
Example:
int ret = 0; while (ret == 0) { ret = evp_agent_loop(ctxt); }
-
int evp_agent_stop(struct evp_agent_context *ctxt)¶
Proceed to stopping the agent.
Shuts down all running instances, and free internal resources.
The agent Status is expected to pass to
EVP_AGENT_STATUS_STOP
when shudown is complete.Note
Currently, the implementation does not support
evp_agent_start()
to be called again after a successful stop.- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
Always return
0
.
-
int evp_agent_free(struct evp_agent_context *ctxt)¶
Free allocated agent context and related resources.
This must be called only after
evp_agent_stop()
had been called.- Parameters:
ctxt – Opaque pointer to internal agent-related data.
Network Connection¶
The network connection can be controlled by the user.
Calling evp_agent_connect()
will initiate connection to the network (Hub and Web).
Agent can then be disconnected
with evp_agent_disconnect()
.
The user may control connection
as they see fit,
as long as it called
after evp_agent_start()
and
before evp_agent_stop()
.
It is standard to initiate connection after agent startup, and disconnect before stopping:
int
main(int argc, char *argv[])
{
struct evp_agent_context *agent = evp_agent_setup(argv[0]);
int ret = evp_agent_start(agent);
if (ret)
goto release;
ret = evp_agent_connect(agent);
if (ret)
goto stop;
while (ret == 0) {
ret = evp_agent_loop(agent);
}
evp_agent_disconnect(agent);
stop:
evp_agent_stop(agent);
release:
evp_agent_free(agent);
return 0;
}
-
int evp_agent_connect(struct evp_agent_context *ctxt)¶
Connect the agent to the Hub.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
Returns zero in case of success or non-zero in case of error.
-
int evp_agent_disconnect(struct evp_agent_context *ctxt)¶
Disconnect the agent from the Hub.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
Returns zero in case of success or non-zero in case of error.
Status¶
It is possible to query
the agent status with evp_agent_get_status()
,
to handle different use cases according
to the agent state.
See evp_agent_status
for reference.
As a convenience,
evp_agent_ready()
queries
the readiness of the agent after startup,
It returns true
if agent
is not in EVP_AGENT_STATUS_INIT
state.
-
enum evp_agent_status¶
- Values:
-
enumerator EVP_AGENT_STATUS_INIT¶
agent has been created but not started
-
enumerator EVP_AGENT_STATUS_READY¶
agent is initialised but not connected
-
enumerator EVP_AGENT_STATUS_CONNECTING¶
agent is waiting for CONNACK
-
enumerator EVP_AGENT_STATUS_CONNECTED¶
agent is connected to hub
-
enumerator EVP_AGENT_STATUS_DISCONNECTING¶
agent is waiting for network operations to finish
-
enumerator EVP_AGENT_STATUS_DISCONNECTED¶
agent is disconnected from network
-
enumerator EVP_AGENT_STATUS_STOPPED¶
agent has been stopped
-
enumerator EVP_AGENT_STATUS_INIT¶
-
enum evp_agent_status evp_agent_get_status(struct evp_agent_context *ctxt)¶
Query the current state of the agent.
-
bool evp_agent_ready(struct evp_agent_context *ctxt)¶
Query the readiness of the agent after startup.
- Parameters:
ctxt – Agent context pointer object
- Returns:
true
if agent is not inEVP_AGENT_STATUS_INIT
state.
Platform¶
Platform allows user to redefine methods that may need specific implementation according to the platform the agent is running on.
A constant evp_agent_platform
object
may be declared and initialized with
the user implemeted methods,
otherwise standard POSIX platform methods
will be used.
A method can be overloaded by defining
it in the user code and initializing
the platform object with the user method.
All pointers left NULL
will not overwrite default methods.
Then the overloaded platform
must be registered with
evp_agent_platform_register()
to set the platform methods.
See Platform documentation.
int evp_agent_platform_register(struct evp_agent_context *ctxt,
const struct evp_agent_platform *p);
Note
This method must be called at most once
before evp_agent_start()
.
Example:
void
my_out_of_memory(const char *file, int line, const char *where, size_t siz)
{
...
}
void *
my_malloc(size_t sz)
{
...
}
void
my_free(void *p)
{
...
}
static struct evp_agent_platform my_platform = {
.out_of_memory = my_out_of_memory,
.secure_malloc = my_malloc,
.secure_free = my_free,
};
int main(const int c, const char *argv[])
{
struct evp_agent_context *agent = evp_agent_setup(argv[0]);
evp_agent_platform_register(agent, &my_platform);
...
return 0;
}
-
struct evp_agent_platform¶
-
int evp_agent_platform_register(struct evp_agent_context *ctxt, const struct evp_agent_platform *p)¶
Set the platform methods.
This method can be called only before
evp_agent_start()
.- Parameters:
ctxt – Opaque pointer to internal agent-related data.
p – pointer to platform methods.
- Returns:
Returns zero on success, non-zero otherwise.
Notification¶
The embedded API provides a way to be notified upon some internal events.
The event to watch must be register with
evp_agent_notification_subscribe()
.
See Notifications documentation.
Example:
int on_reconcile_status(const void *args, void *user_data)
{
struct reconcileStatusNotify *notify_value = args;
printf("Reconcile status of %s is %s", notify_value->deploymentId,
notify_value->reconcileStatus);
return 0;
}
int main(const int c, const char *argv[])
{
struct evp_agent_context *agent = evp_agent_setup(argv[0]);
evp_agent_notification_subscribe(agent, "deployment/reconcileStatus",
NULL);
...
return 0;
}
-
int evp_agent_notification_subscribe(struct evp_agent_context *ctxt, const char *event, int (*cb)(const void *args, void *user_data), void *user_data)¶
Subscribes to an event using a custom callback.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
event – Human-readable string that uniquely identifies the event. It is recommended that event categories are defined similarly to directories i.e., using the forward slash ‘/’ character. For example: “event-group/event” .
cb – User-defined callback to attach to a given event. Several callbacks can be attached to a single event by calling this function repeatedly.
user_data – Opaque pointer to user-defined data. The library shall make no attempts to dereference this pointer, and it can be safely assigned to a null pointer.
- Returns:
Returns zero on success, non-zero otherwise.
Warning
ctxt is currently ignored by this API but a valid pointer must be assigned for future compatibility.
Note
This function will create a deep copy of all of its arguments.
Note
This function is called under the EVP Agent context. In order to ensure the stability of the EVP agent, it is recommended that long-running or blocking user-defined tasks are either avoided or moved to a separate thread.
-
int evp_agent_notification_publish(struct evp_agent_context *ctxt, const char *event, const void *args)¶
Triggers a specific event that will call its associated callbacks.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
event – Human-readable string that uniquely identifies the event.
args – Event-specific arguments. The callback is then responsible to cast this data to the appropriate type.
- Returns:
Returns zero on success, non-zero otherwise.
Deployment¶
Individual instances can be stopped with
evp_agent_stop_instance()
.
There might be little need in production
but is used for testing.
User may request to undeploy
all instances and modules
(for example, before a device reboot).
This can be achieved with evp_agent_undeploy_all()
.
-
int evp_agent_stop_instance(struct evp_agent_context *ctxt, const char *name)¶
Stop a running instance.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
name – Instance name to stop.
- Returns:
Returns zero in case of success or non-zero in case of error.
-
int evp_agent_undeploy_all(struct evp_agent_context *ctxt)¶
Undeploy instances.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
Returns zero in case of success or non-zero in case of error.
-
int evp_agent_empty_deployment_has_completed(struct evp_agent_context *ctxt)¶
Checks whether the deployment reconciliation loop has settled on an empty deployment.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
Returns zero in case of success or non-zero in case of error.
-
int evp_agent_request_pause_deployment(struct evp_agent_context *ctxt)¶
Pause agent deployment capability.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
zero on success
- Returns:
EAGAIN
if deployment cannot be paused yet due to a running operation. User needs to poll again to check that deployment has been successfully paused to guaranty no deployment is in progress.
Note
User can subscribe to deployment/reconcileStatus to be notified when deployment has been successfully paused.
-
int evp_agent_resume_deployment(struct evp_agent_context *ctxt)¶
Resume agent deployment capability.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
- Returns:
zero
Messaging¶
It is possible to inject messages to the agent,
like the Hub would, through MQTT requests,
with evp_agent_send()
.
Even if this has little usage in production,
it is very useful for testing.
Individual instances can be stopped with
evp_agent_stop_instance()
.
There might be little need for this in production
but is useful for testing.
User may request to undeploy
all instances and modules
(for example, before a device reboot).
This can be achieved with evp_agent_undeploy_all()
.
-
int evp_agent_send(struct evp_agent_context *ctxt, const char *topic, const char *payload)¶
Send a message to the agent.
- Parameters:
ctxt – Opaque pointer to internal agent-related data.
topic – Topic string to send.
payload – Payload string to send.
- Returns:
Returns zero in case of success or non-zero in case of error.
Modules¶
This section presents functions related to module state.
-
const char *evp_agent_module_get_id(const struct module *module)¶
Returns the moduleId of a module
- Parameters:
module – Opaque pointer to a module object.
- Returns:
Returns the ID of the module.
-
int evp_agent_module_set_failure_msg(struct module *module, const char *fmt, ...)¶
Sets the failureMessage of a module
- Parameters:
module – Opaque pointer to a module object.
-
bool evp_agent_module_is_in_use(const char *moduleId)¶
Checks if the module is loaded by the agent (in use)
- Parameters:
moduleId – the ID of the module to be checked.
- Returns:
Returns true if module is loaded by the Agent
Thread safety¶
All evp_agent_*()
functions
are mutex protected,
therefore thread-safe.