{"id":19973232,"url":"https://github.com/zeromq/ingescape","last_synced_at":"2025-04-04T12:07:45.621Z","repository":{"id":37087871,"uuid":"397880527","full_name":"zeromq/ingescape","owner":"zeromq","description":"Model-based framework for broker-free distributed software environments. Any language, any OS, web, cloud.","archived":false,"fork":false,"pushed_at":"2024-10-21T12:32:36.000Z","size":357557,"stargazers_count":61,"open_issues_count":4,"forks_count":14,"subscribers_count":21,"default_branch":"main","last_synced_at":"2024-10-23T00:42:09.759Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zeromq.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-19T09:02:02.000Z","updated_at":"2024-10-21T12:32:41.000Z","dependencies_parsed_at":"2023-10-16T04:08:11.098Z","dependency_job_id":"3ca783ed-57e2-4948-a049-136de31ea3d9","html_url":"https://github.com/zeromq/ingescape","commit_stats":{"total_commits":276,"total_committers":18,"mean_commits":"15.333333333333334","dds":0.6557971014492754,"last_synced_commit":"4eefeeb9d1c3f115f3f99dc178f6cb3347afa732"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeromq%2Fingescape","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeromq%2Fingescape/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeromq%2Fingescape/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zeromq%2Fingescape/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zeromq","download_url":"https://codeload.github.com/zeromq/ingescape/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247174418,"owners_count":20896078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T03:10:44.011Z","updated_at":"2025-04-04T12:07:45.603Z","avatar_url":"https://github.com/zeromq.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ingescape - Model-based framework for broker-free distributed software environments\n\n**[Overview](#overview)**\n\n**[Scope and Goals](#scope-and-goals)**\n\n**[Ownership and License](#ownership-and-license)**\n\n**[Dependencies with other open source projects](#dependencies-with-other-open-source-projects)**\n\n**[Building and installing Ingescape](#building-and-installing-ingescape)**\n\n*  [Ingescape and dependencies](#ingescape-and-dependencies)\n*  [Ingescape only](#ingescape-only)\n*  [Testing](#testing)\n*  [Helper scripts](#helper-scripts)\n\n**[Using Ingescape - a simple example (or two)](#using-ingescape---a-simple-example-or-two)**\n\n*  [Modeling the agents](#modeling-the-agents)\n*  [The code and compilation](#the-code-and-compilation)\n*  [Same example using external models as resources](#same-example-using-external-models-as-resources)\n\n**[API Summary](#api-summary)**\n\n**[Hints to contributors](#hints-to-contributors)**\n\n\n\n\n## Overview\nIngescape is a framework for the orchestration of broker-free distributed heterogeneous software (any language, any OS) running on different threads or processes on a computer, different computers on a local network, and different networks, even through the Internet. All these orchestrated distributed software are called Ingescape **agents**. An Ingescape **platform** is a set of agents meshed together and able to communicate in a fully decentralized way.\n\nIngescape brings a neat and easy model-based approach to describe and enforce the communications between agents. The model supports:\n\n- **Data flow** : Agents expose named and typed inputs and outputs. Each agent describes a mapping between its inputs and outputs of other agents resulting in a global data flow architecture. Ingescape data flow uses high-speed, low-latency PUB/SUB communications from outputs of  agents to inputs of other agents, with the optional capability to dispatch data between workers for workload distribution.\n\n\n![three agents mapped together into a platform](./doc/images/three_agents_mapped_together_into_a_platform.png)\n\n- **Request/reply services**: Agents expose named services with named and typed parameters that are equivalent to REST-like web services on one hand and RPC/RMI solutions on the other hand. Any agent can both expose its own services and use services from other agents, without strict client/server segmentations.\n\n![services sequence](./doc/images/services_sequence.png)\n\nBecause Ingescape is developed in C, it can be used out of the box in C++ and Objective-C and bindings can be created for practically any programming language on any operating system. At the moment,  official bindings exist for C#, Python, QML Javascript and NodeJS Javascript. Android Java, Oracle JRE Java and web-app Javascript are also supported with some peculiarities. If you need support for another language, please create an issue or - even better - submit your binding as a merge request!\n\n\n## Scope and Goals\n\nIngescape provides the concepts to build, implement and monitor modern heterogeneous distributed systems with interesting new capabilities. To do so, Ingescape merges the concepts of request/reply communications with the various popular producers/brokers/consumers network patterns, into a consistent, minimal set. The resulting expressivity enables Ingescape to handle 99.9% of the network-based communication patterns, going much further than any third-party technology taken individually. And if you need to go into the 0.1%, ZeroMQ is there as a backup for highly customized architectures.\n\nAt the same time, Ingescape remains open and makes it remarkably easy to interoperate with many other related technologies including Apache Kafka, RabbitMQ, MQTT, OpenDDS, ROS, etc.\n\n**Ingescape platforms are broker-free and fully decentralized.** This means that the Ingescape agents in a distributed platform never rely on any kind of central entity. They are meshed together in a P2P manner and remain as loosely-coupled as possible. On an Ingescape platform, agents can be clients and/or servers, producers and/or consumers, all this at the same time. In this context, Kafka-like or MQTT-like brokers are irrelevant because producers and consumers communicate directly. Most of the time, agents discover one another automatically using UDP broadcast (zbeacons). Ingescape can also use  actual brokers (zgossip), i.e. go-betweens in charge only of putting agents in relation and not misnamed servers whose failure would make the system collapse.\n\n**Ingescape platforms are fully dynamic.** Agents can add, edit or remove inputs, outputs and services at any time. Mappings between inputs and outputs can be added or removed at any time as well. Agents can come and go on a platform as often as they like. Multiple instances of agents are properly supported. In all cases, Ingescape manages the overall consistency automatically and each agent can subscribe to events to get informed and adapt to any of these changes if they need to. Data routing is handled automatically on-the-fly by the Ingescape library in each agent, based on the active mappings at a given time.\n\n**Ingescape is thread-safe with a low code footprint.** In a given software process or application, the Ingescape API enables to create and control one or several agents from any number of threads. This means that existing code is very lightly affected by the introduction of Ingescape: the Ingescape code  integrates surgically with the existing one, independently from the architecture in place. For heavy data computation, Ingescape  integrates seamlessly in the most advanced parallel and multi-threaded architectures, whether to handle received data or to send to other agents.\n\n**Ingescape is multi-transport... And you have nothing to do to benefit from it!** Based on the slick ZeroMQ multi-transport capabilities and Ingescape meshed network, each agent chooses automatically the most efficient transport to support data flows with each other agent. If the two agents are in the same process, shared memory is used. If the agents are on the same computer IPC (for UNIX boxes) or the Loopback (Windows) is used. And for the other cases, TCP is the preferred choice. With this ability, Ingescape agents minimize the latency, increase the bandwidth and optimize the network depending on its actual topology.\n\n**Ingescape is secure.** The Ingescape library supports the ZeroMQ security layer using public/private certificates (SASL, Curve25519, 256 bits keys). This way, agents can validate their identity to others, platforms are joined by allowed agents only (i.e. agents will communicate only if they know each other's identity), and all communications are encrypted.\n\nOther relevant characteristics:\n\n- Ingescape inputs, outputs and services support the following types: impulsions, bool/int/double numbers,  strings, raw binary data.\n- Raw binary data can be of any type and it is simple to use Ingescape in combination with Protobuf.\n- Agents definitions and mappings can be written to and read from an open JSON format support by the Ingescape library.\n- Ingescape comes with logging functions supporting the console, files and data streams to access the logs remotely in real-time.\n- Based on Zyre capabilities, Ingescape supports elections between competing agents, e.g. master/slave determination.\n\n\n## Ownership and License\n\nThe contributors are listed in AUTHORS. This project uses the MPL v2 license, see LICENSE.\nIngescape uses the C4.1 (Collective Code Construction Contract) process for contributions.\nTo report an issue, use the Ingescape issue tracker at github.com.\n\n\n## Dependencies with other open source projects\n\nIngescape relies on the following libraries:\n\n- libzmq as the core network library for the communication between agents using underlying ZeroMQ communication patterns,\n- czmq as a wrapper to the library and for its additional, extremely useful services,\n- zyre as the cornerstone for meshed networks with discovery mechanisms,\n- libsodium for everything crypto.\n\nIngescape also embeds:\n\n-  A lightly modified version of the Yajl JSON parser and generator. See the corresponding source files for related ownership and licence.\n- Uthash for inline macros bringing lists and hash tables.  See the corresponding source files for related ownership and licence.\n\n\n## Building and installing Ingescape\n\nIngescape is  designed primarily to be compiled and installed using cmake, which offers powerful means to generate projects for other types of IDEs or solutions. In addition, Ingescape offers pre-configured projects for the following targets:\n\n- Xcode\n- Qt Creator with both a PRI and a PRO projects\n- Visual studio\n\nBy commodity, Ingescape includes its dependencies as a set of git submodules. Please use the proper git command to pull them as well. The cmake compilation can either compile and install Ingescape and all its dependencies, or compile and install ingescape only, if you want to manage the dependencies externally or if they are already on your system.\n\n\n### Ingescape including dependencies\n\nDependencies are fetched from forks managed by the ingescape team on github and used for long-term industrial maintenance. This is the best way to have a full stack for debugging and contributing to ingescape, using your preferred environment.\n\n\tgit clone --recurse-submodules https://github.com/zeromq/ingescape.git\n\tcd ingescape\n\tmkdir build\n\tcmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DOSX_UNIVERSAL=ON \\\n\t-DCMAKE_OSX_DEPLOYMENT_TARGET=10.11 -DWITH_DEPS=ON\n\tmake -j8 -C build\n\tsudo make -C build install\n\tsudo ldconfig\n\n### Ingescape **NOT** including dependencies\n\nIn this case, all the dependencies need to be fetched and installed individually from their official repositories using the latest master or stable tags. Because Ingescape uses draft APIs from CZMQ and Zyre, compilation might break occasionally depending on their respective evolutions and the delay to make the necessary updates.\n\n    git clone --depth 1 -b stable https://github.com/jedisct1/libsodium.git\n    cd libsodium\n    ./autogen.sh \u0026\u0026 ./configure \u0026\u0026 make check\n    make -j8\n    sudo make install\n    cd ..\n\n    git clone https://github.com/zeromq/libzmq.git\n    cd libzmq\n    mkdir build\n    cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DWITH_LIBSODIUM=ON -DENABLE_DRAFTS=ON -DWITH_TLS=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11\n    make -j8 -C build\n    sudo make -C build install\n    sudo ldconfig\n    cd ..\n\n    git clone https://github.com/zeromq/czmq.git\n    cd czmq\n    mkdir build\n    cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_DRAFTS=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11\n    make -j8 -C build\n    sudo make -C build install\n    sudo ldconfig\n    cd ..\n\n    git clone https://github.com/zeromq/zyre.git\n    cd zyre\n    mkdir build\n    cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_DRAFTS=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11\n    make -j8 -C build\n    sudo make -C build install\n    sudo ldconfig\n    cd ..\n\n    git clone https://github.com/zeromq/ingescape.git\n    cd ingescape\n    mkdir build\n    cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_OSX_DEPLOYMENT_TARGET=10.11\n    make -j8 -C build\n    sudo make -C build install\n    sudo ldconfig\n    cd ..\n\n\n### Testing\nThree test programs are built and installed with Ingescape. They are called *igsTester*,  *igsPartner* and *igsStresser*. They are installed in /usr/local/bin on \\*nix boxes. They enable various series of tests - static and dynamic - to check the library. **They are optional if you are a user and not a contributor.**\n\n#### Static tests on most of the API\n```\n# adjust device and port depending on your computer\nigsTester --device \"en0\" --port 5670 --static\n```\nThese tests call almost all functions in the API and verify their results with assertions. If the program runs properly (despite a lot of expected error messages in the console) and terminates by returning 0, it means that everything went OK.\n\n\n#### Dynamic tests\nIn a console, run:\n```\nigsPartner --device \"en0\" --port 5670 --verbose --auto\n```\nIn another console, run:\n```\nigsTester --device \"en0\" --port 5670 --verbose --auto\n```\nBoth agents discover each other and run tests automatically. If the two programs run properly (despite a lot of expected error messages in the console) and both terminate by returning 0, it means that everything went OK.\n\n#### Stress tests\nOpen one or several consoles and run the following commands, depending on what you want to test.\nFor inputs, outputs and services stress tests, run:\n```\nigsStresser --device en0 --port 5670 --agents 10 --publish --verbose\n```\nFor stress tests on all the aspects at once, run:\n```\nigsStresser --device en0 --port 5670 --agents 10 --deactivate --change_state --change_definition --change_mapping --publish --elections --verbose\n```\n\n#### Interactive tests\nThe two agents also provide advanced console commands to test security, brokers, additional agents in the process, etc.\n\nThe command lines to enable interactive testing are the following:\n```\nigsPartner --device \"en0\" --port 5670 --verbose --interactiveloop\nigsTester --device \"en0\" --port 5670 --verbose --interactiveloop\n\n#in each console, then type /help to display the available console commands\n/help\nAvailable commands in the terminal:\n\t/publish : runs the io publication tests\n\t/services : runs the service tests\n\t/channels : runs the channels tests\n\t/editor agent_uuid : runs the editor (i.e. private bus API) tests on a specific agent\n\t/activate : activates secondAgent\n\t/deactivate : deactivates secondAgent\n\t/service_local : firstAgent calls service secondCall on secondAgent\n\t/gossip : restart in gossip mode\n\t/security : restart and enable security in gossip mode (edit code to use self-discovery instead of gossip)\n\t/quit : quits the agent\n\t/help : displays this message\n```\n\n### Helper scripts\nTwo scripts are provided at the root of the repo:\n\n- **bootstrap_sysroot.sh** is run without any parameter. It creates a *sysroot* directory at the same level as the repo dir and compiles and installs the library and its dependencies inside it. This script also creates the xcode projects for the dependencies, which are necessary for the main xcode project located in builds/xcode and specific to each repo location. If you are not using macos, just ignore the created xcode dirs.\n- **install\\_on\\_system.sh** is a simple commodity script to install Ingescape and its dependencies on your system. This should work on any *nix and windows boxes using cmake.\n\n\n## Using Ingescape - a simple example (or two)\n\nTo illustrate the use of mappings between inputs/outputs and the use of services, we build bogus examples for two agents.\n\n\n### Modeling the agents\n\n**ShapeRecognizer** receives image data on its input and provides a corresponding string with a recognized shape on its output. ShapeRecognizer exposes a getShapeStatistics service expecting a shapeName (string) and a fromDate (integer) as parameters. The getShapeStatistics answers with a receiveShapeStatistics call to the caller, providing a shapeName (string) and a percentage parameters.\n\n**ImagesProvider** receives a string on its shape input and sends bogus image data on its output every second. Every five seconds, it calls the getShapeStatistics service on ShapeRecognizer and exposes a receiveShapeStatistics service to get the answers.\n\nBoth agents are coded to map their input to each other's output. It is illustrated this way :\n\n![example mapping](./doc/images/example_mapping.png)\n\nServices are designed to communicate this way:\n\n![example services sequence](./doc/images/example_services_sequence.png)\n\n\n### The code and compilation\n\nHere is the code for the **ShapeRecognizer** agent to be copied into a main.c file:\n\n\t//\n\t//  main.c\n\t//  ShapeRecognizer version 1.0\n\n\t#ifdef _WIN32\n\t#define WIN32_LEAN_AND_MEAN\n\t#define NOMINMAX\n\t#include \u003cwindows.h\u003e\n\t#include \u003cwinsock2.h\u003e\n\t#endif\n\n\t#include \u003cingescape/ingescape.h\u003e\n\n\tvoid imageCallback(igs_io_type_t ioType, const char* name, igs_io_value_type_t valueType,\n\t                   void* value, size_t valueSize, void* myData){\n\t    igs_info(\"%s received (%zu bytes)\", name, valueSize);\n\t    //doing some sophisticated AI stuff here...\n\t    igs_output_set_string(\"recognizedShape\", \"Rectangle\");\n\t}\n\n\tvoid shapeStatisticsFunction(const char *senderAgentName, const char *senderAgentUUID,\n\t                             const char *callName, igs_service_arg_t *firstArgument, size_t nbArgs,\n\t                             const char *token, void* myData){\n\t    igs_info(\"%s(%s) called %s with parameters:\", senderAgentName, senderAgentUUID, callName);\n\t    igs_info(\"    shapeName : %s\", firstArgument-\u003ec);\n\t    igs_info(\"    from date : %d\", firstArgument-\u003enext-\u003ei);\n\n\t    //composing bogus statistics and sending them\n\t    igs_service_arg_t *list = NULL;\n\t    igs_service_args_add_string(\u0026list, firstArgument-\u003ec);\n\t    igs_service_args_add_int(\u0026list, 65);\n\t    igs_service_call(senderAgentUUID, \"receiveShapeStatistics\", \u0026list, token);\n\t}\n\n\tint main(int argc, const char * argv[]) {\n\t    int nb = 0;\n\t    char **devices = igs_net_devices_list(\u0026nb);\n\t    printf(\"list of network devices for your computer:\\n\");\n\t    for (int i = 0; i \u003c nb; i++)\n\t        printf(\" %s\\n\", devices[i]);\n\t    printf(\"Use one of them in igs_start_with_device.\\n\");\n\t    igs_free_net_devices_list(devices, nb);\n\n\t    igs_log_set_console(true);\n\t    igs_log_set_file(true, NULL);\n\t    igs_log_set_stream(true);\n\t    igs_agent_set_name(\"ShapeRecognizer\");\n\n\t    igs_definition_set_version(\"1.0\");\n\n\t    igs_input_create(\"image\", IGS_DATA_T, 0, 0);\n\t    igs_observe_input(\"image\", imageCallback, NULL);\n\t    igs_mapping_add(\"image\", \"ImagesProvider\", \"image\"); //map our image input to the ImagesProvider agent\n\n\t    igs_output_create(\"recognizedShape\", IGS_STRING_T, 0, 0);\n\n\t    igs_service_init(\"getShapeStatistics\", shapeStatisticsFunction, NULL);\n\t    igs_service_arg_add(\"getShapeStatistics\",\"shapeName\", IGS_STRING_T);\n\t    igs_service_arg_add(\"getShapeStatistics\",\"fromDate\", IGS_INTEGER_T);\n\n\t    igs_start_with_device(\"en0\", 5670); //customize the network device based on your computer\n\n\t    getchar(); //returns when entering any character in the console\n\n\t    igs_stop();\n\t    return 0;\n\t}\n\n\nAnd here is how to compile it in a minimal way using gcc:\n\n\tgcc -Wall -g -I/usr/local/include/ -std=gnu99 -o main.o -c main.c\n\tgcc -o ShapeRecognizer main.o -L/usr/local/lib -lingescape\n\t./ShapeRecognizer\n\nThe compilation requires  linking against the Ingescape library only.\n\nHere is the code for the **ImagesProvider** agent to be copied into another main.c file:\n\n\t//\n\t//  main.c\n\t//  ImagesProvider version 1.0\n\t//  Created by Stéphane Valès on 2021/07/23\n\n\t#ifdef _WIN32\n\t#ifndef WIN32_LEAN_AND_MEAN\n\t#define WIN32_LEAN_AND_MEAN\n\t#endif\n\t#define NOMINMAX\n\t#include \u003cwindows.h\u003e\n\t#include \u003cwinsock2.h\u003e\n\t#endif\n\n\t#include \u003cingescape/ingescape.h\u003e\n\n\tvoid shapeCallback(igs_io_type_t ioType, const char* name, igs_io_value_type_t valueType,\n\t                   void* value, size_t valueSize, void* myData){\n\t    igs_info(\"%s recognized as %s\", name, (char*)value);\n\t}\n\n\tvoid shapeStatisticsFunction(const char *senderAgentName, const char *senderAgentUUID,\n\t                             const char *callName, igs_service_arg_t *firstArgument, size_t nbArgs,\n\t                             const char *token, void* myData){\n\t    igs_info(\"%s(%s) called %s with parameters:\", senderAgentName, senderAgentUUID, callName);\n\t    igs_info(\"    shapeName : %s\", firstArgument-\u003ec);\n\t    igs_info(\"    percentage : %d\", firstArgument-\u003enext-\u003ei);\n\t}\n\n\tint publishImage(zloop_t *loop, int timer_id, void *arg){\n\t    void *image = malloc(128); //create bogus data\n\t    igs_output_set_data(\"image\", image, 128);\n\t    free(image);\n\t    igs_info(\"publish image data\");\n\t    return 0;\n\t}\n\n\tint askStatistics(zloop_t *loop, int timer_id, void *arg){\n\t    igs_service_arg_t *list = NULL;\n\t    igs_service_args_add_string(\u0026list, \"Rectangle\");\n\t    igs_service_args_add_int(\u0026list, 1627033669);\n\t    igs_service_call(\"ShapeRecognizer\", \"getShapeStatistics\", \u0026list, \"bogus_query_id\");\n\t    igs_info(\"ask ShapeRecognizer for statistics using getShapeStatistics service\");\n\t    return 0;\n\t}\n\n\tint main(int argc, const char * argv[]) {\n\t    int nb = 0;\n\t    char **devices = igs_net_devices_list(\u0026nb);\n\t    printf(\"list of network devices for your computer:\\n\");\n\t    for (int i = 0; i \u003c nb; i++)\n\t        printf(\" %s\\n\", devices[i]);\n\t    printf(\"Use one of them in igs_start_with_device.\\n\");\n\t    igs_free_net_devices_list(devices, nb);\n\n\t    igs_log_set_console(true);\n\t    igs_log_set_file(true, NULL);\n\t    igs_log_set_stream(true);\n\t    igs_agent_set_name(\"ImagesProvider\");\n\n\t    igs_definition_set_version(\"1.0\");\n\n\t    igs_input_create(\"shape\", IGS_STRING_T, 0, 0);\n\t    igs_observe_input(\"shape\", shapeCallback, NULL);\n\t    igs_mapping_add(\"shape\", \"ShapeRecognizer\", \"recognizedShape\");\n\n\t    igs_output_create(\"image\", IGS_DATA_T, 0, 0);\n\n\t    igs_service_init(\"receiveShapeStatistics\", shapeStatisticsFunction, NULL);\n\t    igs_service_arg_add(\"receiveShapeStatistics\",\"shapeName\", IGS_STRING_T);\n\t    igs_service_arg_add(\"receiveShapeStatistics\",\"percentage\", IGS_INTEGER_T);\n\n\t    igs_start_with_device(\"en0\", 5670); //customize the network device based on your computer\n\n\t    zloop_t *loop = zloop_new();\n\t    zloop_timer(loop, 1000, 0, publishImage, NULL);\n\t    zloop_timer(loop, 5000, 0, askStatistics, NULL);\n\t    zloop_start(loop); //will terminate on interruption or Ctrl+C\n\n\t    igs_stop();\n\t    return 0;\n\t}\n\nAnd here is how to compile it in a minimal way using gcc:\n\n\tgcc -Wall -g -I/usr/local/include/ -std=gnu99 -o main.o -c main.c\n\tgcc -o ImagesProvider main.o -L/usr/local/lib -lingescape -lczmq\n\t./ImagesProvider\n\nBecause with use a CZMQ zloop in our example, the compilation requires linking against the Ingescape and CZMQ libraries.\n\nYou may be surprised by the almost complete absence of network code in these examples. This is the main objective of Ingescape: focusing on the exchanging data rather than on managing network connections. For the two agents to discover each other and establish communication, there is only one line of code that matters:\n\n\tigs_start_with_device(\"en0\", 5670); //customize the network device based on your computer\n\nThis function starts an agent on the network, using a network device on your computer and a network port that shall be free from any TCP binding. The list of network devices for your computer is displayed by this code:\n\n\tint nb = 0;\n\tchar **devices = igs_net_devices_list(\u0026nb);\n\tprintf(\"list of network devices for your computer:\\n\");\n\tfor (int i = 0; i \u003c nb; i++)\n\t\tprintf(\" %s\\n\", devices[i]);\n\tprintf(\"Use one of them in igs_start_with_device.\\n\");\n\tigs_free_net_devices_list(devices, nb);\n\nDepending on your computer and operating system, network device names may be very different. On Windows, you may expect things like \"Ethernet 2\", \"Wi-Fi\" or \"Loopback\". On UNIX systems, expect things like \"eth0\" or \"en0\". If the list is empty, this means that no active network device exists on your computer and that you should enable WiFi or plug an ethernet cable.\nBetween two agents on the same computer, use the same device and port. Between two agents on two different computers, use the same port and devices connected to the same local network. When this is done, the two agents discover and connect to each other automatically.\n\nWhen the two agents are finally running on the same port, on the same network device or same local network, images published by ImagesProvider on its image output are received by ShapeRecognizer on its image input. When this happens, ShapeRecognizer publishes a recognized shape on its recognizedShape output, that is finally received by ImagesProvider on its shape input. In the same way, getShapeStatistics and receiveShapeStatistics services answer one to the other. All communications (output publication and service call) are initiated by ImagesProvider based on the two zloop timers.\n\nCommunications can be checked in the console or in the log files that are create in ~/Documents/Ingescape/logs.\n\n\n### Same example using external models as resources\n\nThe Ingescape library supports models for the definitions of the agents and their mapping inside a given platform. There are two ways to declare a model:\n\n- Using the API to hardcode it\n- Loading a JSON resource file representing the model\n\nHere is the JSON definition for **ShapeRecognizer**:\n```\n{\n    \"definition\": {\n        \"name\": \"ShapeRecognizer\",\n        \"version\": \"1.0\",\n        \"inputs\": [\n            {\n                \"name\": \"image\",\n                \"type\": \"DATA\"\n            }\n        ],\n        \"outputs\": [\n            {\n                \"name\": \"recognizedShape\",\n                \"type\": \"STRING\",\n                \"value\": \"\"\n            }\n        ],\n        \"attributes\": [\n\n        ],\n        \"services\": [\n            {\n                \"name\": \"getShapeStatistics\",\n                \"arguments\": [\n                    {\n                        \"name\": \"shapeName\",\n                        \"type\": \"STRING\"\n                    },\n                    {\n                        \"name\": \"fromDate\",\n                        \"type\": \"INTEGER\"\n                    }\n                ]\n            }\n        ]\n    }\n}\n```\n\nAnd here is the JSON mapping for **ShapeRecognizer**:\n```\n{\n    \"mappings\": [\n        {\n            \"fromInput\": \"image\",\n            \"toAgent\": \"ImagesProvider\",\n            \"toOutput\": \"image\"\n        }\n    ],\n    \"splits\": [\n\n    ]\n}\n```\n\nInstead of using the API to hardcode the definition and the mapping, the two JSON files can be loaded as external resources. The modified code in the main function is as follows:\n\n\tint main(int argc, const char * argv[]) {\n\t\tint nb = 0;\n\t\tchar **devices = igs_net_devices_list(\u0026nb);\n\t\tprintf(\"list of network devices for your computer:\\n\");\n\t\tfor (int i = 0; i \u003c nb; i++)\n\t\t    printf(\" %s\\n\", devices[i]);\n\t\tprintf(\"Use one of them in igs_start_with_device.\\n\");\n\t\tigs_free_net_devices_list(devices, nb);\n\n\t\tigs_log_set_console(true);\n\t\tigs_log_set_file(true, NULL);\n\t\tigs_log_set_stream(true);\n\t\tigs_definition_load_file(\"ShapeRecognizer.json\");\n\t\tigs_mapping_load_file(\"ShapeRecognizer_mapping.json\");\n\n\t\tigs_observe_input(\"image\", imageCallback, NULL);\n\n\t\tigs_service_init(\"getShapeStatistics\", shapeStatisticsFunction, NULL);\n\n\t\tigs_start_with_device(\"en0\", 5670); //customize the network device based on your computer\n\n\t\tgetchar(); //returns when entering any character in the console\n\n\t\tigs_stop();\n\t\treturn 0;\n\t}\n\nAll the functions used to create inputs, outputs, services and their arguments become useless when loading a model. The only remaining functions are the ones enabling to observe inputs and link services with the actual code. The models also cover the creation of mapping entries, avoiding specific code for this.\n\n## API Summary\n\nThe Ingescape library comes with two headers. The _ingescape.h_ header is dedicated to the global functions and the API to use when you only have one agent in your process or application. The second header, _igsagent.h_, provides all the specific functions dedicated to several agents inside the same process. Basically, _igsagent.h_ provides a subset of the _ingescape.h_ functions with a different prefix and an agent pseudo-object as first parameter, plus new/destroy/activate/deactivate specific capabilities.\n\nThe global Ingescape API is centralized in a single header file. The header is heavily commented, with examples when it is relevant.\nHere is the structure of ingescape.h:\n\n- Agent initialization, control and events\n- Editing \u0026 inspecting definitions, adding and removing inputs/outputs\n- Reading and writing inputs/outputs\n- Handling attributes\n- Mappings edition \u0026 inspection\n- Services edition \u0026 inspection\n- Timers\n- Communicating via channels\n- Brokers (when self-discovery is not possible)\n- Security\n- Elections and leadership between agents\n- Administration, logging, configuration and utilities\n\t- Logging functions\n\t- Version, command line, logging parameters, definition and mapping path, IPC transport configuration\n\t- Advanced network configuration and monitoring\n- JSON parsing and generation\n\n\n## Hints to contributors\n\nIngescape has built an architecture and data exchange model above some amazing ZeroMQ technologies. Please keep that in mind to decide where to contribute between CZMQ, Zyre and Ingescape.\n\nThe Ingescape API does not fully comply  with the CLASS style guide yet but progressively gets closer. We already share its objectives of simplicity and minimalism. Do read your code after you write it and ask, \"Can I make this simpler?\"\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeromq%2Fingescape","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzeromq%2Fingescape","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzeromq%2Fingescape/lists"}