Compare commits
	
		
			3 Commits
		
	
	
		
			8ff0f13109
			...
			f83abab0a0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f83abab0a0 | |||
| bd30bc8fd5 | |||
| f9eae6ede9 | 
							
								
								
									
										3
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/cd.yml
									
									
									
									
										vendored
									
									
								
							| @@ -47,10 +47,11 @@ jobs: | ||||
|         submodules: recursive | ||||
|  | ||||
|     - name: Install Dependencies | ||||
|       # TODO: is 2.6 new enough? | ||||
|       run: sudo apt update && sudo apt -y install nix | ||||
|  | ||||
|     - name: Nix build | ||||
|       run: nix build '.#static' | ||||
|       run: nix --extra-experimental-features nix-command build '.#static' | ||||
|  | ||||
|     - uses: actions/upload-artifact@v3 | ||||
|       with: | ||||
|   | ||||
							
								
								
									
										134
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										134
									
								
								src/main.cpp
									
									
									
									
									
								
							| @@ -15,6 +15,11 @@ | ||||
| #include "./message_cleanser.hpp" | ||||
| #include "./message_command_dispatcher.hpp" | ||||
|  | ||||
| #include <solanaceae/message3/components.hpp> | ||||
| #include <solanaceae/contact/components.hpp> | ||||
| #include <solanaceae/tox_contacts/components.hpp> | ||||
| #include <solanaceae/toxcore/utils.hpp> | ||||
|  | ||||
| #include <nlohmann/json.hpp> | ||||
|  | ||||
| #include <chrono> | ||||
| @@ -165,12 +170,13 @@ int main(int argc, char** argv) { | ||||
| 		mcd.registerCommand( | ||||
| 			"host", "", | ||||
| 			"info", | ||||
| 			[](std::string_view) -> bool { | ||||
| 			[](std::string_view, Message3Handle m) -> bool { | ||||
| 				std::cout << "INFO got called :)\n"; | ||||
| 				return true; | ||||
| 			}, | ||||
| 			"Get basic information about this bot" | ||||
| 		); | ||||
|  | ||||
| 	} | ||||
|  | ||||
| 	PluginManager pm; | ||||
| @@ -197,10 +203,134 @@ int main(int argc, char** argv) { | ||||
| 	ToxMessageManager tmm{rmm, cr, tcm, tc, tc}; | ||||
| 	ToxTransferManager ttm{rmm, cr, tcm, tc, tc}; | ||||
|  | ||||
| 	{ // setup more advanced commands | ||||
| 		mcd.registerCommand( | ||||
| 			"tox", "tox", | ||||
| 			"status", | ||||
| 			[&](std::string_view, Message3Handle m) -> bool { | ||||
| 				const auto tox_self_status = tc.toxSelfGetConnectionStatus(); | ||||
|  | ||||
| 				const auto contact_from = m.get<Message::Components::ContactFrom>().c; | ||||
|  | ||||
| 				std::string reply{"dht:"}; | ||||
|  | ||||
| 				if (tox_self_status == Tox_Connection::TOX_CONNECTION_UDP) { | ||||
| 					reply += "upd-direct"; | ||||
| 				} else if (tox_self_status == Tox_Connection::TOX_CONNECTION_TCP) { | ||||
| 					reply += "tcp-relayed"; | ||||
| 				} | ||||
|  | ||||
| 				if (cr.all_of<Contact::Components::ToxFriendEphemeral>(contact_from)) { | ||||
| 					const auto con_opt = tc.toxFriendGetConnectionStatus(cr.get<Contact::Components::ToxFriendEphemeral>(contact_from).friend_number); | ||||
| 					if (!con_opt.has_value() || con_opt.value() == Tox_Connection::TOX_CONNECTION_NONE) { | ||||
| 						reply += "\nfriend:offline"; | ||||
| 					} else if (con_opt.value() == Tox_Connection::TOX_CONNECTION_UDP) { | ||||
| 						reply += "\nfriend:udp-direct"; | ||||
| 					} else if (con_opt.value() == Tox_Connection::TOX_CONNECTION_TCP) { | ||||
| 						reply += "\nfriend:tcp-relayed"; | ||||
| 					} | ||||
| 				} else if (cr.all_of<Contact::Components::ToxGroupPeerEphemeral>(contact_from)) { | ||||
| 					const auto [group_number, peer_number] = cr.get<Contact::Components::ToxGroupPeerEphemeral>(contact_from); | ||||
|  | ||||
| 					const auto [con_opt, _] = tc.toxGroupPeerGetConnectionStatus(group_number, peer_number); | ||||
| 					if (!con_opt.has_value() || con_opt.value() == Tox_Connection::TOX_CONNECTION_NONE) { | ||||
| 						reply += "\ngroup-peer:offline"; | ||||
| 					} else if (con_opt.value() == Tox_Connection::TOX_CONNECTION_UDP) { | ||||
| 						reply += "\ngroup-peer:udp-direct"; | ||||
| 					} else if (con_opt.value() == Tox_Connection::TOX_CONNECTION_TCP) { | ||||
| 						reply += "\ngroup-peer:tcp-relayed"; | ||||
| 					} | ||||
| 				} else if (cr.any_of<Contact::Components::ToxFriendPersistent, Contact::Components::ToxGroupPeerPersistent>(contact_from)) { | ||||
| 					reply += "\noffline"; | ||||
| 				} else { | ||||
| 					reply += "\nunk"; | ||||
| 				} | ||||
|  | ||||
| 				rmm.sendText( | ||||
| 					contact_from, | ||||
| 					reply | ||||
| 				); | ||||
|  | ||||
| 				return true; | ||||
| 			}, | ||||
| 			"Query the tox status of dht and to you." | ||||
| 		); | ||||
|  | ||||
| 		mcd.registerCommand( | ||||
| 			"tox", "tox", | ||||
| 			"add", | ||||
| 			[&](std::string_view params, Message3Handle m) -> bool { | ||||
| 				const auto contact_from = m.get<Message::Components::ContactFrom>().c; | ||||
|  | ||||
| 				if (params.size() != 38*2) { | ||||
| 					rmm.sendText( | ||||
| 						contact_from, | ||||
| 						"error adding friend, id is not the correct size!" | ||||
| 					); | ||||
| 					return true; | ||||
| 				} | ||||
|  | ||||
| 				// TODO: add tcm interface | ||||
| 				const auto [_, err] = tc.toxFriendAdd(hex2bin(std::string{params}), "Add me, I am totato"); | ||||
|  | ||||
| 				if (err == Tox_Err_Friend_Add::TOX_ERR_FRIEND_ADD_OK) { | ||||
| 					rmm.sendText( | ||||
| 						contact_from, | ||||
| 						"freind request sent" | ||||
| 					); | ||||
| 				} else { | ||||
| 					rmm.sendText( | ||||
| 						contact_from, | ||||
| 						"error adding friend, error code " + std::to_string(err) | ||||
| 					); | ||||
| 				} | ||||
|  | ||||
| 				return true; | ||||
| 			}, | ||||
| 			"add a tox friend by id" | ||||
| 		); | ||||
|  | ||||
| 		mcd.registerCommand( | ||||
| 			"tox", "tox", | ||||
| 			"join", | ||||
| 			[&](std::string_view params, Message3Handle m) -> bool { | ||||
| 				const auto contact_from = m.get<Message::Components::ContactFrom>().c; | ||||
|  | ||||
| 				if (params.size() != 32*2) { | ||||
| 					rmm.sendText( | ||||
| 						contact_from, | ||||
| 						"error joining group, id is not the correct size!" | ||||
| 					); | ||||
| 					return true; | ||||
| 				} | ||||
|  | ||||
| 				auto name_opt = conf.get_string("tox", "name"); | ||||
|  | ||||
| 				// TODO: add tcm interface | ||||
| 				const auto [_, err] = tc.toxGroupJoin(hex2bin(std::string{params}), std::string{name_opt.value_or("no-name-found")}, ""); | ||||
| 				if (err == Tox_Err_Group_Join::TOX_ERR_GROUP_JOIN_OK) { | ||||
| 					rmm.sendText( | ||||
| 						contact_from, | ||||
| 						"joining group..." | ||||
| 					); | ||||
| 				} else { | ||||
| 					rmm.sendText( | ||||
| 						contact_from, | ||||
| 						"error joining group, error code " + std::to_string(err) | ||||
| 					); | ||||
| 				} | ||||
|  | ||||
| 				return true; | ||||
| 			}, | ||||
| 			"join a tox group by id" | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	{ // setup plugin instances | ||||
| 		g_provideInstance<ConfigModelI>("ConfigModelI", "host", &conf); | ||||
| 		g_provideInstance<Contact3Registry>("Contact3Registry", "host", &cr); | ||||
| 		g_provideInstance<RegistryMessageModel>("RegistryMessageModel", "host", &rmm); | ||||
| 		g_provideInstance<MessageCommandDispatcher>("MessageCommandDispatcher", "host", &mcd); | ||||
|  | ||||
| 		g_provideInstance<ToxI>("ToxI", "host", &tc); | ||||
| 		g_provideInstance<ToxPrivateI>("ToxPrivateI", "host", &tpi); | ||||
| @@ -249,6 +379,8 @@ int main(int argc, char** argv) { | ||||
|  | ||||
| 		mc.iterate(0.02f); | ||||
|  | ||||
| 		mcd.iterate(0.02f); | ||||
|  | ||||
| 		//std::this_thread::sleep_for( // time left to get to 60fps | ||||
| 			//std::chrono::duration<float, std::chrono::seconds::period>(0.0166f) // 60fps frame duration | ||||
| 			//- std::chrono::duration<float, std::chrono::seconds::period>(std::chrono::steady_clock::now() - new_time) // time used for rendering | ||||
|   | ||||
| @@ -3,8 +3,11 @@ | ||||
| #include <solanaceae/util/config_model.hpp> | ||||
| #include <solanaceae/message3/components.hpp> | ||||
|  | ||||
| #include <string_view> | ||||
| #include <utility> | ||||
| #include <iostream> | ||||
| #include <vector> | ||||
| #include <map> | ||||
|  | ||||
| //MessageCommandDispatcher::Command::Command(Command&& other) : | ||||
| 	//m(std::move(other.m)), | ||||
| @@ -29,8 +32,8 @@ MessageCommandDispatcher::MessageCommandDispatcher( | ||||
| 		registerCommand( | ||||
| 			"host", "", | ||||
| 			"help", | ||||
| 			[this](std::string_view params) -> bool { | ||||
| 				return helpCommand(params); | ||||
| 			[this](std::string_view params, Message3Handle m) -> bool { | ||||
| 				return helpCommand(params, m); | ||||
| 			}, | ||||
| 			"Get help" | ||||
| 		); | ||||
| @@ -40,11 +43,19 @@ MessageCommandDispatcher::MessageCommandDispatcher( | ||||
| MessageCommandDispatcher::~MessageCommandDispatcher(void) { | ||||
| } | ||||
|  | ||||
| void MessageCommandDispatcher::iterate(float time_delta) { | ||||
| void MessageCommandDispatcher::iterate(float) { | ||||
| 	if (!_message_queue.empty()) { | ||||
| 		_rmm.sendText( | ||||
| 			_message_queue.front().to, | ||||
| 			_message_queue.front().message | ||||
| 		); | ||||
| 		_message_queue.pop_front(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static std::string_view get_first_word(std::string_view text) { | ||||
| static std::string_view get_first_word(std::string_view text, std::string_view::size_type& out_next) { | ||||
| 	if (text.empty()) { | ||||
| 		out_next = std::string_view::npos; | ||||
| 		return text; | ||||
| 	} | ||||
|  | ||||
| @@ -52,17 +63,21 @@ static std::string_view get_first_word(std::string_view text) { | ||||
| 	const auto pos_first_non_space = text.find_first_not_of(' '); | ||||
| 	if (pos_first_non_space == std::string_view::npos) { | ||||
| 		// only contains spaces o.o | ||||
| 		return ""; // should return text as is? | ||||
| 		out_next = std::string_view::npos; | ||||
| 		return ""; | ||||
| 	} | ||||
|  | ||||
| 	text = text.substr(pos_first_non_space); | ||||
| 	out_next += pos_first_non_space; | ||||
|  | ||||
| 	const auto pos_first_space = text.find_first_of(' '); | ||||
| 	if (pos_first_space == 0 || pos_first_space == std::string_view::npos) { | ||||
| 		// does not contain spaces | ||||
| 		// command is whole message | ||||
| 		out_next = std::string_view::npos; | ||||
| 		return text; | ||||
| 	} else { | ||||
| 		out_next += pos_first_space; | ||||
| 		return text.substr(0, pos_first_space); | ||||
| 	} | ||||
| } | ||||
| @@ -71,10 +86,10 @@ void MessageCommandDispatcher::registerCommand( | ||||
| 	std::string_view m, // module | ||||
| 	std::string_view m_prefix, // module prefix (if any) | ||||
| 	std::string_view command, // command | ||||
| 	std::function<bool(std::string_view params)>&& fn, | ||||
| 	std::function<bool(std::string_view params, Message3Handle m)>&& fn, | ||||
| 	std::string_view help_text | ||||
| ) { | ||||
| 	std::string full_command_string = std::string{m_prefix} + std::string{command}; | ||||
| 	std::string full_command_string = (m_prefix.empty() ? "" : std::string{m_prefix} + " ") + std::string{command}; | ||||
|  | ||||
| 	if (_command_map.count(full_command_string)) { | ||||
| 		std::cout << "MCD warning: overwriting existing '" << full_command_string << "'\n"; | ||||
| @@ -89,8 +104,42 @@ void MessageCommandDispatcher::registerCommand( | ||||
| 	}; | ||||
| } | ||||
|  | ||||
| bool MessageCommandDispatcher::helpCommand(std::string_view params) { | ||||
| bool MessageCommandDispatcher::helpCommand(std::string_view params, Message3Handle m) { | ||||
| 	std::cout << "MCD: help got called '" << params << "'\n"; | ||||
|  | ||||
| 	std::map<std::string, std::vector<decltype(_command_map.cbegin())>> module_command_list; | ||||
| 	for (auto it = _command_map.cbegin(); it != _command_map.cend(); it++) { | ||||
| 		if (true) { // have permission | ||||
| 			module_command_list[it->second.m].push_back(it); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	const auto contact_from = m.get<Message::Components::ContactFrom>().c; | ||||
|  | ||||
| 	for (const auto& [module_name, command_list] : module_command_list) { | ||||
| 		_message_queue.push_back({ | ||||
| 			contact_from, | ||||
| 			"=== " + module_name + " ===" | ||||
| 		}); | ||||
|  | ||||
| 		for (const auto& it : command_list) { | ||||
| 			std::string help_line {"  !"}; | ||||
| 			if (!it->second.m_prefix.empty()) { | ||||
| 				help_line += it->second.m_prefix + " "; | ||||
| 			} | ||||
|  | ||||
| 			help_line += it->second.command; | ||||
|  | ||||
| 			help_line += " - "; | ||||
| 			help_line += it->second.help_text; | ||||
|  | ||||
| 			_message_queue.push_back({ | ||||
| 				contact_from, | ||||
| 				help_line | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| @@ -158,20 +207,35 @@ bool MessageCommandDispatcher::onEvent(const Message::Events::MessageConstruct& | ||||
|  | ||||
| 	std::string_view first_word; | ||||
| 	std::string_view second_word; | ||||
| 	std::string_view::size_type pos_next = 0; | ||||
|  | ||||
| 	first_word = get_first_word(message_text); | ||||
| 	std::cout << "------- first_word:'" << first_word << "'\n"; | ||||
| 	first_word = get_first_word(message_text, pos_next); | ||||
| 	std::cout << "------- first_word:'" << first_word << "' pos_next:" << pos_next << "\n"; | ||||
| 	if (first_word.size() != message_text.size()) { | ||||
| 		second_word = get_first_word( | ||||
| 			message_text.substr( | ||||
| 				// TODO: optimize this | ||||
| 				message_text.find(first_word) | ||||
| 				+ first_word.size() | ||||
| 			) | ||||
| 			message_text.substr(pos_next), | ||||
| 			pos_next | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| 	std::cout << "------- second_word:'" << second_word << "' empty:" << second_word.empty() << "\n"; | ||||
| 	std::cout << "------- second_word:'" << second_word << "' empty:" << second_word.empty() << " pos_next:" << pos_next << "\n"; | ||||
|  | ||||
| 	std::string params; | ||||
| 	if (pos_next != std::string_view::npos && message_text.size() > pos_next+1) { | ||||
| 		auto tmp_params = message_text.substr(pos_next); | ||||
|  | ||||
| 		const auto params_pos_first_non_space = tmp_params.find_first_not_of(' '); | ||||
| 		if (params_pos_first_non_space == std::string_view::npos) { | ||||
| 			tmp_params = {}; | ||||
| 		} else if (params_pos_first_non_space != 0) { | ||||
| 			// trim leading whitespace | ||||
| 			tmp_params = tmp_params.substr(params_pos_first_non_space); | ||||
| 		} | ||||
|  | ||||
| 		params = tmp_params; | ||||
|  | ||||
| 		std::cout << "------- params:'" << params << "'\n"; | ||||
| 	} | ||||
|  | ||||
| 	// first search first + space + second word | ||||
| 	if (!second_word.empty()) { | ||||
| @@ -181,7 +245,7 @@ bool MessageCommandDispatcher::onEvent(const Message::Events::MessageConstruct& | ||||
|  | ||||
| 		const auto command_it = _command_map.find(query); | ||||
| 		if (command_it != _command_map.cend()) { | ||||
| 			command_it->second.fn(message_text); | ||||
| 			command_it->second.fn(params, e.e); | ||||
| 			return true; | ||||
| 		} | ||||
| 	} | ||||
| @@ -189,7 +253,8 @@ bool MessageCommandDispatcher::onEvent(const Message::Events::MessageConstruct& | ||||
| 	// then seach first word only | ||||
| 	const auto command_it = _command_map.find(std::string{first_word}); | ||||
| 	if (command_it != _command_map.cend()) { | ||||
| 		command_it->second.fn(message_text); | ||||
| 		params = std::string{second_word} + " " + params; | ||||
| 		command_it->second.fn(params, e.e); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,8 @@ | ||||
|  | ||||
| #include <solanaceae/message3/registry_message_model.hpp> | ||||
|  | ||||
| #include <deque> | ||||
|  | ||||
| // fwd | ||||
| struct ConfigModelI; | ||||
|  | ||||
| @@ -14,13 +16,19 @@ class MessageCommandDispatcher : public RegistryMessageModelEventI { | ||||
| 		std::string m; // module | ||||
| 		std::string m_prefix; // module prefix (if any) | ||||
| 		std::string command; // command | ||||
| 		std::function<bool(std::string_view params)> fn; | ||||
| 		std::function<bool(std::string_view params, Message3Handle m)> fn; | ||||
| 		std::string help_text; | ||||
|  | ||||
| 		//Command(const Command&) = delete; | ||||
| 	}; | ||||
| 	std::unordered_map<std::string, Command> _command_map; | ||||
|  | ||||
| 	struct QueuedMessage { | ||||
| 		Contact3 to; | ||||
| 		std::string message; | ||||
| 	}; | ||||
| 	std::deque<QueuedMessage> _message_queue; | ||||
|  | ||||
| 	public: | ||||
| 		MessageCommandDispatcher(Contact3Registry& cr, RegistryMessageModel& rmm, ConfigModelI& conf); | ||||
| 		~MessageCommandDispatcher(void); | ||||
| @@ -40,12 +48,12 @@ class MessageCommandDispatcher : public RegistryMessageModelEventI { | ||||
| 			std::string_view m, // module | ||||
| 			std::string_view m_prefix, // module prefix (if any) | ||||
| 			std::string_view command, // command | ||||
| 			std::function<bool(std::string_view params)>&& fn, | ||||
| 			std::function<bool(std::string_view params, Message3Handle m)>&& fn, | ||||
| 			std::string_view help_text | ||||
| 		); | ||||
|  | ||||
| 		// generates a help | ||||
| 		bool helpCommand(std::string_view params); | ||||
| 		bool helpCommand(std::string_view params, Message3Handle m); | ||||
|  | ||||
| 	protected: // mm | ||||
| 		bool onEvent(const Message::Events::MessageConstruct& e) override; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user