mirror of
https://gitlab.com/niansa/llama_any.git
synced 2025-03-06 20:48:27 +01:00
Initial commit
This commit is contained in:
commit
06f836c0d4
12 changed files with 779 additions and 0 deletions
74
.gitignore
vendored
Normal file
74
.gitignore
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
CMakeLists.txt.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
30
CMakeLists.txt
Normal file
30
CMakeLists.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(llama.any LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
add_executable(llama
|
||||
main.cpp
|
||||
Client.hpp Client.cpp
|
||||
Socket.hpp
|
||||
Receiver.hpp Receiver.cpp
|
||||
Sender.hpp Sender.cpp
|
||||
Runtime.cpp Runtime.hpp
|
||||
)
|
||||
|
||||
target_compile_definitions(llama PUBLIC PLATFORM="${CMAKE_SYSTEM_NAME}")
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL Nintendo3DS)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_3DS)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL NintendoDS)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_DS)
|
||||
target_link_libraries(llama PUBLIC dswifi9 nds9)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_LINUX)
|
||||
elseif (CMAKE_SYSTEM_NAME STREQUAL Windows)
|
||||
target_compile_definitions(llama PUBLIC PLATFORM_WINDOWS)
|
||||
target_link_libraries(llama PUBLIC Ws2_32)
|
||||
else()
|
||||
message(SEND_ERROR "${CMAKE_SYSTEM_NAME} is not a supported platform!")
|
||||
endif()
|
113
Client.cpp
Normal file
113
Client.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "Client.hpp"
|
||||
#include "Socket.hpp"
|
||||
#include "Sender.hpp"
|
||||
#include "Receiver.hpp"
|
||||
|
||||
#include <cerrno>
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <netdb.h>
|
||||
#else
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void Client::fetchAddr(const std::string& addr, unsigned port) {
|
||||
# ifdef HAS_ADDRINFO
|
||||
// Set up hints
|
||||
addrinfo hints;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_INET; //TODO: Care about IPv6
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
|
||||
// Get port as C string
|
||||
char portStr[7];
|
||||
sprintf(portStr, "%u", port);
|
||||
|
||||
// Get addrinfo
|
||||
auto error = getaddrinfo(addr.c_str(), portStr, &hints, &addrInfo);
|
||||
auto bad = addrInfo == nullptr;
|
||||
# else
|
||||
addrInfo = gethostbyname(addr.c_str());
|
||||
auto error = errno;
|
||||
auto bad = addrInfo == nullptr || addrInfo->h_addr_list[0] == nullptr;
|
||||
# endif
|
||||
|
||||
// Check for error
|
||||
if (bad) {
|
||||
throw Exception("DNS failed to look up hostname: "+std::string(strerror(error))+" ("+addr+')');
|
||||
}
|
||||
}
|
||||
|
||||
Client::Client(const std::string& addr, unsigned port) {
|
||||
// Create socket
|
||||
connection = std::make_unique<SocketConnection<Sender::Simple, Receiver::Simple>>(Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); //TODO: Care about IPv6
|
||||
if (*connection < 0) [[unlikely]] {
|
||||
throw Exception("Failed to create TCP socket");
|
||||
}
|
||||
|
||||
// Fetch address
|
||||
fetchAddr(addr, port);
|
||||
|
||||
# ifdef HAS_ADDRINFO
|
||||
// Connect to server
|
||||
if (connect(*connection, addrInfo->ai_addr, addrInfo->ai_addrlen) != 0) [[unlikely]] {
|
||||
throw Exception("Connection for HTTP::Request has been declined");
|
||||
}
|
||||
# else
|
||||
// Connect to server
|
||||
struct sockaddr_in sain;
|
||||
sain.sin_family = AF_INET;
|
||||
sain.sin_port = htons(port);
|
||||
sain.sin_addr.s_addr = *reinterpret_cast<unsigned long *>(addrInfo->h_addr_list[0]);
|
||||
if (connect(*connection, reinterpret_cast<sockaddr *>(&sain), sizeof(sain)) != 0) [[unlikely]] {
|
||||
throw Exception("Connection has been declined");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
void Client::ask(std::string_view prompt, const std::function<void (unsigned progress)>& on_progress, const std::function<void (std::string_view token)>& on_token) {
|
||||
std::string fres;
|
||||
|
||||
// Send prompt length
|
||||
uint8_t len = prompt.length();
|
||||
connection->writeObject(len, true);
|
||||
|
||||
// Send prompt
|
||||
connection->write(prompt);
|
||||
|
||||
// Receive progress
|
||||
for (;;) {
|
||||
uint8_t progress;
|
||||
|
||||
// Receive percentage
|
||||
connection->readObject(progress);
|
||||
|
||||
// Run on_progress callback
|
||||
on_progress(progress);
|
||||
|
||||
// Stop at 100%
|
||||
if (progress == 100) break;
|
||||
}
|
||||
|
||||
// Receive response
|
||||
for (;;) {
|
||||
// Receive response length
|
||||
connection->readObject(len);
|
||||
|
||||
// End if zero
|
||||
if (len == 0xFF) break;
|
||||
|
||||
// Receive response
|
||||
const auto token = connection->read(len);
|
||||
|
||||
// Run on_token callback
|
||||
on_token(token);
|
||||
}
|
||||
}
|
45
Client.hpp
Normal file
45
Client.hpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#ifndef CLIENT_HPP
|
||||
#define CLIENT_HPP
|
||||
#include "Runtime.hpp"
|
||||
#include "Socket.hpp"
|
||||
#include "Sender.hpp"
|
||||
#include "Receiver.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
# include <netdb.h>
|
||||
#else
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
|
||||
class Client
|
||||
{
|
||||
struct Exception : public std::runtime_error {
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
int fd = -1;
|
||||
# ifdef HAS_ADDRINFO
|
||||
addrinfo
|
||||
# else
|
||||
bool sent = false;
|
||||
hostent
|
||||
# endif
|
||||
*addrInfo; // Can't be null unless request has already been sent
|
||||
|
||||
std::unique_ptr<SocketConnection<Sender::Simple, Receiver::Simple>> connection;
|
||||
|
||||
void fetchAddr(const std::string& addr, unsigned port);
|
||||
|
||||
public:
|
||||
Client(const std::string &addr, unsigned port);
|
||||
|
||||
void ask(std::string_view prompt, const std::function<void (unsigned progress)>& on_progress, const std::function<void (std::string_view token)>& on_token);
|
||||
};
|
||||
|
||||
#endif // CLIENT_HPP
|
43
Receiver.cpp
Normal file
43
Receiver.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "Receiver.hpp"
|
||||
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
# include <sys/select.h>
|
||||
# include <sys/socket.h>
|
||||
#else
|
||||
# include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
std::string Receiver::Simple::read(size_t amount) {
|
||||
// Create buffer
|
||||
std::string fres;
|
||||
fres.resize(amount);
|
||||
|
||||
// Read into buffer
|
||||
read(reinterpret_cast<std::byte*>(fres.data()), fres.size());
|
||||
|
||||
// Return final buffer
|
||||
return fres;
|
||||
}
|
||||
void Receiver::Simple::read(std::byte *buffer, size_t size) {
|
||||
recv(fd, buffer, size, MSG_WAITALL);
|
||||
}
|
||||
|
||||
std::string Receiver::Simple::readSome(size_t max) {
|
||||
// Create buffer
|
||||
std::string fres;
|
||||
fres.resize(max);
|
||||
|
||||
// Receive data
|
||||
ssize_t bytesRead;
|
||||
if ((bytesRead = recv(fd, fres.data(), max, MSG_WAITALL)) < 0) [[unlikely]] {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Resize and return final buffer
|
||||
fres.resize(bytesRead);
|
||||
return fres;
|
||||
}
|
30
Receiver.hpp
Normal file
30
Receiver.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef _RECEIVER_HPP
|
||||
#define _RECEIVER_HPP
|
||||
#include "Runtime.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
namespace Receiver {
|
||||
class Simple {
|
||||
protected:
|
||||
int fd;
|
||||
|
||||
public:
|
||||
Simple(int fd) : fd(fd) {}
|
||||
|
||||
// Reads the exact amount of bytes given
|
||||
std::string read(size_t amount);
|
||||
void read(std::byte *buffer, size_t size);
|
||||
// Reads at max. the amount of bytes given
|
||||
std::string readSome(size_t max);
|
||||
|
||||
// Reads an object of type T
|
||||
template<typename T>
|
||||
auto readObject(T& o) {
|
||||
return read(reinterpret_cast<std::byte *>(&o), sizeof(o));
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
47
Runtime.cpp
Normal file
47
Runtime.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#include "Runtime.hpp"
|
||||
|
||||
#ifdef PLATFORM_3DS
|
||||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
#include <cerrno>
|
||||
#include <3ds.h>
|
||||
|
||||
|
||||
|
||||
void Runtime::customTerminate() noexcept {
|
||||
// Get error message
|
||||
std::string message;
|
||||
try {
|
||||
std::rethrow_exception(std::current_exception());
|
||||
} catch (const std::exception& e) {
|
||||
message = e.what();
|
||||
} catch (...) {
|
||||
message = "Unknown";
|
||||
}
|
||||
// Display error
|
||||
errorConf conf = {
|
||||
.type = ERROR_TEXT_WORD_WRAP,
|
||||
.errorCode = errno,
|
||||
.upperScreenFlag = ERROR_NORMAL,
|
||||
.useLanguage = CFG_LANGUAGE_EN,
|
||||
.Text = {L'I', L'N', L'V', L'A', L'L', L'I', L'D', L'\0'},
|
||||
.homeButton = true,
|
||||
.softwareReset = false,
|
||||
.appJump = false,
|
||||
.returnCode = ERROR_UNKNOWN,
|
||||
.eulaVersion = 0
|
||||
};
|
||||
errorText(&conf, ("An exception was thrown but never handled:\n\n"+message).c_str());
|
||||
errorDisp(&conf);
|
||||
// Exit
|
||||
aptExit();
|
||||
socExit();
|
||||
gfxExit();
|
||||
exit(-errno);
|
||||
}
|
||||
#elif PLATFORM_DS
|
||||
void Runtime::kbCallback(int key) {
|
||||
if (key > 0) printf("%c", key);
|
||||
}
|
||||
#endif
|
235
Runtime.hpp
Normal file
235
Runtime.hpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
#ifndef _RUNTIME_HPP
|
||||
#define _RUNTIME_HPP
|
||||
|
||||
#ifdef PLATFORM_3DS
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include <malloc.h>
|
||||
#include <3ds.h>
|
||||
|
||||
|
||||
class Runtime {
|
||||
u32 *SOC_buffer = NULL;
|
||||
constexpr static auto SOC_ALIGN = 0x1000,
|
||||
SOC_BUFFERSIZE = 0x100000;
|
||||
|
||||
[[noreturn]] static void customTerminate() noexcept;
|
||||
|
||||
public:
|
||||
Runtime() {
|
||||
std::set_terminate(customTerminate);
|
||||
gfxInitDefault();
|
||||
consoleInit(GFX_TOP, NULL);
|
||||
aptInit();
|
||||
SOC_buffer = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE);
|
||||
auto ret = socInit(SOC_buffer, SOC_BUFFERSIZE);
|
||||
if (ret != 0) {
|
||||
throw std::runtime_error("socInit() = "+std::to_string((unsigned int)ret));
|
||||
}
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
~Runtime() {
|
||||
aptSetHomeAllowed(false);
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
std::clog << std::endl << "Runtime destroyed." << std::endl;
|
||||
std::clog << "Press START to exit" << std::flush;
|
||||
for (u32 kDown; !(hidKeysDown() & KEY_START) && cooperate(); hidScanInput()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
aptExit();
|
||||
socExit();
|
||||
gfxExit();
|
||||
}
|
||||
|
||||
static inline
|
||||
bool cooperate() noexcept {
|
||||
return aptMainLoop();
|
||||
}
|
||||
|
||||
static const char *readInput(const char *hint) {
|
||||
static SwkbdState swkbd;
|
||||
static char swkbd_buf[2048];
|
||||
// Read input
|
||||
memset(swkbd_buf, 0, sizeof(swkbd_buf));
|
||||
swkbdInit(&swkbd, SWKBD_TYPE_NORMAL, 3, sizeof(swkbd_buf));
|
||||
swkbdSetHintText(&swkbd, hint);
|
||||
swkbdInputText(&swkbd, swkbd_buf, sizeof(swkbd_buf));
|
||||
// Return input as string
|
||||
return swkbd_buf;
|
||||
}
|
||||
|
||||
static void clearScreen() {
|
||||
consoleClear();
|
||||
}
|
||||
};
|
||||
#elif PLATFORM_DS
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <malloc.h>
|
||||
#include <nds.h>
|
||||
#include <dswifi9.h>
|
||||
|
||||
|
||||
class Runtime {
|
||||
static void kbCallback(int key);
|
||||
|
||||
Keyboard *swkbd;
|
||||
|
||||
public:
|
||||
Runtime() {
|
||||
// Initialize console
|
||||
consoleDemoInit();
|
||||
|
||||
// Initialize WiFi
|
||||
std::cout << "Connecting via WFC data" << std::endl;
|
||||
if (!Wifi_InitDefault(WFC_CONNECT)) {
|
||||
throw std::runtime_error("Failed to enable WiFi");
|
||||
}
|
||||
|
||||
// Initialize keyboard
|
||||
swkbd = keyboardDemoInit();
|
||||
swkbd->OnKeyPressed = kbCallback;
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
~Runtime() {}
|
||||
|
||||
static inline
|
||||
bool cooperate() noexcept {
|
||||
// The Nintendo DS does not support multitasking
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *readInput(const char *hint) {
|
||||
std::cout << hint << ": " << std::flush;
|
||||
static std::string outstr;
|
||||
std::getline(std::cin, outstr);
|
||||
return outstr.c_str();
|
||||
}
|
||||
|
||||
static void clearScreen() {
|
||||
consoleClear();
|
||||
}
|
||||
};
|
||||
#elif PLATFORM_LINUX
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <mutex>
|
||||
#include <cstring>
|
||||
#include <csignal>
|
||||
#include <cerrno>
|
||||
|
||||
|
||||
|
||||
class Runtime {
|
||||
static inline bool stopping = false;
|
||||
static inline void handler(int signo, siginfo_t *info, void *context) {
|
||||
stopping = true;
|
||||
}
|
||||
|
||||
public:
|
||||
Runtime() {
|
||||
struct sigaction act = { 0 };
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_sigaction = handler;
|
||||
for (int sig : {SIGTERM, SIGINT, SIGQUIT, SIGHUP}) {
|
||||
if (sigaction(sig, &act, nullptr) < 0) {
|
||||
throw std::runtime_error("sigaction() = "+std::string(strerror(errno)));
|
||||
}
|
||||
}
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
~Runtime() {
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
std::clog << std::endl << "Runtime destroyed." << std::endl;
|
||||
}
|
||||
|
||||
static inline bool cooperate() noexcept {
|
||||
// Linux runs threads preemptively, no need to actually cooperate
|
||||
return !stopping;
|
||||
}
|
||||
|
||||
static const char *readInput(const char *hint) {
|
||||
static std::string content;
|
||||
std::cout << hint << ": ";
|
||||
std::getline(std::cin, content);
|
||||
return content.c_str();
|
||||
}
|
||||
|
||||
static void clearScreen() {
|
||||
std::cout << "\033[H\033[2J\033[3J";
|
||||
}
|
||||
};
|
||||
#elif PLATFORM_WINDOWS
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <winsock2.h>
|
||||
|
||||
|
||||
|
||||
class Runtime {
|
||||
public:
|
||||
Runtime() {
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
|
||||
throw std::runtime_error("Failed to initialize WinSock");
|
||||
}
|
||||
}
|
||||
Runtime(Runtime&) = delete;
|
||||
Runtime(const Runtime&) = delete;
|
||||
Runtime(Runtime&&) = delete;
|
||||
~Runtime() {
|
||||
std::cout << std::flush;
|
||||
std::cerr << std::flush;
|
||||
std::clog << std::endl << "Runtime destroyed." << std::endl;
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
static constexpr bool cooperate() noexcept {
|
||||
// Windows runs threads preemptively, no need to cooperate.
|
||||
// No signals to handle either, Windows doesn't support them.
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *readInput(const char *hint) {
|
||||
static std::string content;
|
||||
std::cout << hint << ": ";
|
||||
std::getline(std::cin, content);
|
||||
return content.c_str();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !(defined(PLATFORM_WINDOWS) || defined(PLATFORM_DS))
|
||||
# define MSG_FLAGS_OR_ZERO(...) __VA_ARGS__
|
||||
#else
|
||||
# define MSG_FLAGS_OR_ZERO(...) 0
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_DS
|
||||
# define IPPROTO_TCP 0
|
||||
#endif
|
||||
|
||||
#ifndef PLATFORM_DS
|
||||
# define HAS_ADDRINFO
|
||||
#endif
|
24
Sender.cpp
Normal file
24
Sender.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "Runtime.hpp"
|
||||
#include "Sender.hpp"
|
||||
|
||||
#include <string_view>
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
# include <sys/socket.h>
|
||||
# include <sys/select.h>
|
||||
#else
|
||||
# include <ws2tcpip.h>
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void Sender::Simple::write(std::string_view str, bool moreData) {
|
||||
this->write(reinterpret_cast<const std::byte*>(str.data()), str.size(), moreData);
|
||||
}
|
||||
|
||||
void Sender::Simple::write(const std::byte *data, size_t size, bool moreData) {
|
||||
std::string fres;
|
||||
|
||||
// Write
|
||||
send(fd, reinterpret_cast<const char*>(data), size, MSG_FLAGS_OR_ZERO(MSG_WAITALL | MSG_NOSIGNAL | (int(moreData)*MSG_MORE)));
|
||||
}
|
25
Sender.hpp
Normal file
25
Sender.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef _SENDER_HPP
|
||||
#define _SENDER_HPP
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
namespace Sender {
|
||||
class Simple {
|
||||
protected:
|
||||
int fd;
|
||||
|
||||
public:
|
||||
Simple(int fd) : fd(fd) {}
|
||||
|
||||
void write(std::string_view, bool moreData = false);
|
||||
void write(const std::byte *data, size_t, bool moreData = false);
|
||||
|
||||
template<typename T>
|
||||
auto writeObject(const T& o, bool moreData = false) {
|
||||
return write(reinterpret_cast<const std::byte *>(&o), sizeof(o), moreData);
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
68
Socket.hpp
Normal file
68
Socket.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef _SOCKET_HPP
|
||||
#define _SOCKET_HPP
|
||||
#include <memory>
|
||||
#include <unistd.h>
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
# include <ws2tcpip.h>
|
||||
#elif defined(PLATFORM_WII)
|
||||
#include <network.h>
|
||||
#else
|
||||
# include <sys/socket.h>
|
||||
# include <sys/select.h>
|
||||
#endif
|
||||
|
||||
|
||||
class Socket {
|
||||
int fd;
|
||||
|
||||
protected:
|
||||
void reset() {
|
||||
fd = -1;
|
||||
}
|
||||
void set(int _fd) {
|
||||
fd = _fd;
|
||||
}
|
||||
|
||||
public:
|
||||
using Port = uint16_t;
|
||||
|
||||
Socket() : fd(-1) {}
|
||||
Socket(int domain, int type, int protocol) {
|
||||
fd = socket(domain, type, protocol);
|
||||
}
|
||||
Socket(Socket&) = delete;
|
||||
Socket(const Socket&) = delete;
|
||||
Socket(Socket&& o) : fd(o.fd) {
|
||||
o.fd = -1;
|
||||
}
|
||||
auto& operator =(Socket&& o) {
|
||||
close(fd);
|
||||
fd = o.fd;
|
||||
o.fd = -1;
|
||||
return *this;
|
||||
}
|
||||
~Socket() {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
operator int() const {
|
||||
return fd;
|
||||
}
|
||||
|
||||
int get() const {
|
||||
return fd;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class SenderT, class ReceiverT>
|
||||
class SocketConnection : public SenderT, public ReceiverT, public Socket {
|
||||
public:
|
||||
SocketConnection(Socket&& socket)
|
||||
// Double-initialization seems to yield better assembly
|
||||
: SenderT(socket), ReceiverT(socket), Socket(std::move(socket)) {
|
||||
SenderT::fd = get();
|
||||
ReceiverT::fd = get();
|
||||
}
|
||||
};
|
||||
#endif
|
45
main.cpp
Normal file
45
main.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "Runtime.hpp"
|
||||
#include "Client.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
|
||||
void on_progress(float progress) {
|
||||
std::cout << unsigned(progress) << '\r' << std::flush;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
Runtime rt;
|
||||
|
||||
// Print header
|
||||
std::cout << "llama.any running on " PLATFORM ".\n"
|
||||
"\n";
|
||||
|
||||
// Ask for server address
|
||||
const std::string addr = rt.readInput("Server address");
|
||||
|
||||
// Create client
|
||||
Client client(addr, 99181);
|
||||
|
||||
// Connection loop
|
||||
for (;; rt.cooperate()) {
|
||||
// Clear screen
|
||||
rt.clearScreen();
|
||||
|
||||
// Run inference
|
||||
client.ask(rt.readInput("Prompt"), [&rt] (float progress) {
|
||||
std::cout << unsigned(progress) << "%\r" << std::flush;
|
||||
rt.cooperate();
|
||||
}, [&rt] (std::string_view token) {
|
||||
std::cout << token << std::flush;
|
||||
rt.cooperate();
|
||||
});
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue