{"id":22620454,"url":"https://github.com/sebsikora/satellite_terminal","last_synced_at":"2025-03-29T02:13:20.881Z","repository":{"id":201446284,"uuid":"432259257","full_name":"sebsikora/satellite_terminal","owner":"sebsikora","description":"Easily spawn and communicate bidirectionally with client processes in separate terminal emulator instances","archived":false,"fork":false,"pushed_at":"2021-12-06T18:05:31.000Z","size":4200,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-03T12:17:12.293Z","etag":null,"topics":["client-server","cpp-library","cpp-tool","debugging-tools","multi-process","multi-window","process-communication","terminal-based","terminal-library","terminal-tools"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sebsikora.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-11-26T17:45:34.000Z","updated_at":"2022-05-09T07:46:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"757b1658-949a-41c3-a0e8-f79c09366538","html_url":"https://github.com/sebsikora/satellite_terminal","commit_stats":null,"previous_names":["sebsikora/satellite_terminal"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebsikora%2Fsatellite_terminal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebsikora%2Fsatellite_terminal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebsikora%2Fsatellite_terminal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sebsikora%2Fsatellite_terminal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sebsikora","download_url":"https://codeload.github.com/sebsikora/satellite_terminal/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246126720,"owners_count":20727594,"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":["client-server","cpp-library","cpp-tool","debugging-tools","multi-process","multi-window","process-communication","terminal-based","terminal-library","terminal-tools"],"created_at":"2024-12-08T22:13:49.932Z","updated_at":"2025-03-29T02:13:20.864Z","avatar_url":"https://github.com/sebsikora.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# satellite_terminal\n\u003cbr /\u003e\n\n![Parent and Child process terminal emulator instances](screenshot.png)\n\u003cbr /\u003e\n\n© 2021 Dr Sebastien Sikora.\n\n[seb.nf.sikora@protonmail.com](mailto:seb.nf.sikora@protonmail.com)\n\u003cbr /\u003e\n\u003cbr /\u003e\n\nA simple C++ library for POSIX compatible operating systems that enables your project to easily launch and communicate bidirectionally with client processes connected to separate terminal emulator instances.\n\u003cbr /\u003e\n\nUpdated 06/12/2021.\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n## What is it?\n\nsatellite_terminal automates the process of launching a client process connected to it's own terminal emulator instance from within a parent process, linked with an arbitrary number of [named pipes](https://en.wikipedia.org/wiki/Named_pipe)(otherwise known as FIFOs) to allow bidirectional interprocess communication.\n\nsatellite_terminal leverages the functionality defined in the [unistd.h](https://en.wikipedia.org/wiki/Unistd.h), [sys/stat.h](https://en.wikibooks.org/wiki/C_Programming/POSIX_Reference/sys/stat.h) \u0026 [fcntl.h](https://pubs.opengroup.org/onlinepubs/007904875/basedefs/fcntl.h.html) headers, and as-such will work only with [POSIX compatible](https://en.wikipedia.org/wiki/POSIX) operating systems and [environments](https://www.cygwin.com/). satellite_terminal has to-date been compiled and tested on GNU/Linux.\n\nsatellite_terminal is easy to incorporate and use within your own projects, as the basic examples below will demonstrate.\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n## How to use it?\n\nUsing satellite_terminal in a C++ project is very easy. Let's demonstrate this via a simple example.\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n### Parent process\n\nIn the parent process, we spawn the child process by instantiating a `SatTerm_Server`. At a minimum, we pass the server constructor an identifier string and a string comprising the path to the child process binary as arguments. We can set the third (optional) boolean argument to `false` to hide console information and error messages for both parent and child process.\n\nThe fourth (optional) argument is a vector of `Port` identifiers. By default a single send-receive pair of FIFOs will be created, accessed via a single corresponding `Port` (\"comms\") instantiated by each of the `SatTerm_Server` and `SatTerm_Client`. If desired we can specify an arbitrary number of additional `Port` identifiers here.\n\u003cbr /\u003e\n\n```cpp\n// parent.cpp\n#include \"satellite_terminal.h\"\n...\n\n// Server constructor prototype in satellite_terminal.h:\n//\n// SatTerm_Server(std::string const\u0026 identifier, std::string const\u0026 path_to_client_binary, bool display_messages = true,\n//                std::vector\u003cstd::string\u003e port_identifiers = {\"comms\"}, std::string const\u0026 stop_message = \"q\",\n//                std::string const\u0026 path_to_terminal_emulator_paths = \"./terminal_emulator_paths.txt\",\n//                char end_char = 3, std::string const\u0026 stop_port_identifier = \"\", unsigned long timeout_seconds = 5);\n\nSatTerm_Server sts(\"test_server\", \"./child_binary\");\n\n// Path to child binary above can incorporate desired command-line arguments\n// eg: \"./child_binary --full-screen=true\"\n\nif (sts.IsConnected()) {\n\t// We are good to go!\n\t...\n}\n...\n```\n\u003cbr /\u003e\n\nThe server constructor will spawn a terminal emulator (from the list in `terminal_emulator_paths.txt`) via-which it will directly execute the child binary using the ['-e' option](https://www.mankier.com/1/xterm#-e), passing the required configuration options for the child process via automatically generated command-line options.\n\nThe server constructor will return once the communication channel is established with the child process, an error occurs or a timeout is reached. When it returns, if the server's `IsConnected()` member function returns `true`, the child process started correctly and the required FIFOs were created and opened for reading/writing without error.\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n### Child process\n\nIn the child process, we establish communication with the parent process by instantiating a `SatTerm_Client`. The client parameters are passed to the child process via command-line arguments, therefore argc and argv must be passed to the constructor.\n\nThe parameters are appended directly onto the child binary path string passed to the server constructor, following an automatically applied delimiter (\"client_args\"), so you can use any command-line arguments required by the child process as normal and the client constructor will automatically parse the remaining arguments.\n\u003cbr /\u003e\n\n```cpp\n// child.cpp\n#include \"satellite_terminal.h\"\n\nint main(int argc, char *argv[]) {\n\t\n\t// -- Your argument parser goes here ---\n\t//      -- Don't modify argc/v! --\n\t\n\tSatTerm_Client stc(\"test_client\", argc, argv);\n\t\n\tif (stc.IsConnected()) {\n\t\t// We are good to go!\n\t\t...\n\t}\n...\n```\n\u003cbr /\u003e\n\nThe client constructor will return once the communication channel is established with the parent process, an error occurs or a timeout is reached. When it returns, if the client's `IsConnected()` member function returns `true`, the bi-directional communication channel was established without error.\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n### Sending and receiving\n\nOnce the `SatTerm_Server` constructor in our parent process and `SatTerm_Client` constructor in our spawned child process have returned our two processes can exchange messages.\n\n\n\u003cbr /\u003e\n\n```cpp\n// SendMessage() function prototype in satellite_terminal.h:\n//\n// std::string SendMessage(std::string const\u0026 message, size_t tx_fifo_index = 0, unsigned long timeout_seconds = 10);\n\nstd::string message_unsent = stc.SendMessage(\"Outbound message\");\n\n\n// GetMessage() function prototype in satellite_terminal.h:\n//\n// std::string GetMessage(size_t rx_fifo_index = 0, bool capture_end_char = false, unsigned long timeout_seconds = 0);\n\nstd::string inbound_message = stc.GetMessage();\n\n```\n\u003cbr /\u003e\n\nBlah [blah]() `blah.cpp`.\n\nBlah.\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n## Complete basic example\n\nBlah...\n\u003cbr /\u003e\n\n```cpp\n// server_demo.cpp\n\n#include \u003cunistd.h\u003e                 // sleep(), usleep().\n#include \u003cctime\u003e                    // time().\n#include \u003ciostream\u003e                 // std::cout, std::cerr, std::endl.\n#include \u003cstring\u003e                   // std::string.\n\n#include \"satellite_terminal.h\"\n\nint main (void) {\n\t\n\tSatTerm_Server sts(\"test_server\", \"./client_demo\");\n\t\n\tif (sts.IsConnected()) {\n\t\tsize_t message_count = 10;\n\t\tfor (size_t i = 0; i \u003c message_count; i ++) {\n\t\t\tstd::string outbound_message = \"Message number \" + std::to_string(i) + \" from server.\";\n\t\t\tsts.SendMessage(outbound_message);\n\t\t}\n\t\t\n\t\tunsigned long timeout_seconds = 5;\n\t\tunsigned long start_time = time(0);\n\t\t\n\t\twhile ((sts.GetErrorCode().err_no == 0) \u0026\u0026 ((time(0) - start_time) \u003c timeout_seconds)) {\n\t\t\tstd::string inbound_message = sts.GetMessage();\n\t\t\tif (inbound_message != \"\") {\n\t\t\t\tstd::cout \u003c\u003c \"Message \\\"\" \u003c\u003c inbound_message \u003c\u003c \"\\\" returned by client.\" \u003c\u003c std::endl;\n\t\t\t}\n\t\t\tusleep(1000);\n\t\t}\n\t\t\n\t\tstd::cerr \u003c\u003c \"On termination error code = \" \u003c\u003c sts.GetErrorCode().err_no \u003c\u003c \"    Error detail = \" \u003c\u003c sts.GetErrorCode().detail \u003c\u003c std::endl;\n\t\t\n\t} else {\n\t\t\n\t\tstd::cerr \u003c\u003c \"On termination error code = \" \u003c\u003c sts.GetErrorCode().err_no \u003c\u003c \"    Error detail = \" \u003c\u003c sts.GetErrorCode().detail \u003c\u003c std::endl;\n\t\t\n\t}\n\treturn 0;\n}\n```\n\u003cbr /\u003e\n\nBlah...\n\u003cbr /\u003e\n\n```cpp\n// client_demo.cpp\n\n#include \u003cunistd.h\u003e                 // sleep(), usleep().\n#include \u003cctime\u003e                    // time().\n#include \u003ciostream\u003e                 // std::cout, std::cerr, std::endl.\n#include \u003cstring\u003e                   // std::string.\n\n#include \"satellite_terminal.h\"\n\nint main(int argc, char *argv[]) {\n\t\n\tSatTerm_Client stc(\"test_client\", argc, argv);\n\n\tif (stc.IsConnected()) {\n\t\t\n\t\twhile (stc.GetErrorCode().err_no == 0) {\n\t\t\t\n\t\t\tstd::string inbound_message = stc.GetMessage();\n\t\t\t\n\t\t\tif (inbound_message != \"\") {\n\t\t\t\tstd::cout \u003c\u003c inbound_message \u003c\u003c std::endl;\n\t\t\t\tif (inbound_message != stc.GetStopMessage()) {\n\t\t\t\t\tstc.SendMessage(inbound_message);\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t\n\t\t\t}\n\t\t\tusleep(1000);\n\t\t}\n\t\tstd::cerr \u003c\u003c \"On termination error code = \" \u003c\u003c stc.GetErrorCode().err_no \u003c\u003c \"    Error detail = \" \u003c\u003c stc.GetErrorCode().detail \u003c\u003c std::endl;\n\t\tsleep(5);        // Delay to read the message before terminal emulator window closes.\n\t} else {\n\t\tstd::cerr \u003c\u003c \"On termination error code = \" \u003c\u003c stc.GetErrorCode().err_no \u003c\u003c \"    Error detail = \" \u003c\u003c stc.GetErrorCode().detail \u003c\u003c std::endl;\n\t\tsleep(5);        // Delay to read the message before terminal emulator window closes.\n\t}\n\treturn 0;\n}\n```\n\u003cbr /\u003e\n\nCompile `server_demo.cpp` and `client_demo.cpp`, then execute `server_demo` from within the project directory:\n\u003cbr /\u003e\n\n```\nuser@home:~/Documents/cpp_projects/satellite_terminal$ g++  -Wall -g -O3 -I src/ src/satterm_agent.cpp src/satterm_client.cpp src/satterm_server.cpp src/satterm_port.cpp demos/server_demo.cpp -o server_demo\nuser@home:~/Documents/cpp_projects/satellite_terminal$ g++  -Wall -g -O3 -I src/ src/satterm_agent.cpp src/satterm_client.cpp src/satterm_server.cpp src/satterm_port.cpp demos/client_demo.cpp -o client_demo\nuser@home:~/Documents/cpp_projects/satellite_terminal$ ./server_demo \nServer working path is /home/user/Documents/cpp_projects/satellite_terminal/\nClient process started.\nClient process attempting to execute via terminal emulator '-e':\n./client_demo client_args /home/user/Documents/cpp_projects/satellite_terminal/ 3 q 1 1 server_rx server_tx\nTrying /usr/bin/x-terminal-emulator\nIn Port server_rx opened fifo /home/user/Documents/cpp_projects/satellite_terminal/server_rx for reading on descriptor 3\nOut Port server_tx opened fifo /home/user/Documents/cpp_projects/satellite_terminal/server_tx for writing on descriptor 4\nServer test_server successfully initialised connection.\nMessage \"Message number 0 from server.\" returned by client.\nMessage \"Message number 1 from server.\" returned by client.\nMessage \"Message number 2 from server.\" returned by client.\nMessage \"Message number 3 from server.\" returned by client.\nMessage \"Message number 4 from server.\" returned by client.\nMessage \"Message number 5 from server.\" returned by client.\nMessage \"Message number 6 from server.\" returned by client.\nMessage \"Message number 7 from server.\" returned by client.\nMessage \"Message number 8 from server.\" returned by client.\nMessage \"Message number 9 from server.\" returned by client.\nOn termination error code = 0    Error detail = \nWaiting for client process to terminate...\nEOF error on GetMessage() for In Port server_rx suggests counterpart terminated.\nuser@home:~/Documents/cpp_projects/satellite_terminal$\n```\n\u003cbr /\u003e\n\nOutput in child terminal emulator instance:\n\u003cbr /\u003e\n\n```\nClient working path is /home/user/Documents/cpp_projects/satellite_terminal/\nOut Port server_rx opened fifo /home/user/Documents/cpp_projects/satellite_terminal/server_rx for writing on descriptor 3\nIn Port server_tx opened fifo /home/user/Documents/cpp_projects/satellite_terminal/server_tx for reading on descriptor 4\nClient test_client successfully initialised connection.\nMessage number 0 from server.\nMessage number 1 from server.\nMessage number 2 from server.\nMessage number 3 from server.\nMessage number 4 from server.\nMessage number 5 from server.\nMessage number 6 from server.\nMessage number 7 from server.\nMessage number 8 from server.\nMessage number 9 from server.\nq\nOn termination error code = 0    Error detail = \n```\n\u003cbr /\u003e\n\nBlah...\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n## License:\n\u003cbr /\u003e\n\n![Mit License Logo](./220px-MIT_logo.png)\n\u003cbr /\u003e\n\u003cbr /\u003e\n\nsatellite_terminal is distributed under the terms of the MIT license.\nLearn about the MIT license [here](https://choosealicense.com/licenses/mit/)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsebsikora%2Fsatellite_terminal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsebsikora%2Fsatellite_terminal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsebsikora%2Fsatellite_terminal/lists"}