modified: clients/awk/sync/src/un.awk

modified:   clients/c/src/un.c
	modified:   clients/clojure/sync/src/un.clj
	modified:   clients/cobol/sync/src/un.cob
	modified:   clients/cpp/sync/src/un.cpp
	modified:   clients/crystal/sync/src/un.cr
	modified:   clients/d/sync/src/un.d
	modified:   clients/dart/sync/src/un.dart
	modified:   clients/elixir/sync/src/un.ex
	modified:   clients/erlang/sync/src/un.erl
	modified:   clients/forth/sync/src/un.forth
	modified:   clients/fortran/sync/src/un.f90
	modified:   clients/fsharp/sync/src/un.fs
	modified:   clients/haskell/sync/src/un.hs
	modified:   clients/julia/sync/src/un.jl
	modified:   clients/kotlin/sync/src/un.kt
	modified:   clients/lisp/sync/src/un.lisp
	modified:   clients/nim/sync/src/un.nim
	modified:   clients/ocaml/sync/src/un.ml
	modified:   clients/powershell/sync/src/un.ps1
	modified:   clients/prolog/sync/src/un.pro
	modified:   clients/r/sync/src/un.r
	modified:   clients/scheme/sync/src/un.scm
	modified:   clients/tcl/sync/src/un.tcl
	modified:   clients/typescript/sync/src/un.ts
	modified:   clients/v/sync/src/un.v
	modified:   clients/zig/sync/src/un.zig
This commit is contained in:
russell@unturf.com 2026-01-17 12:01:42 -05:00
parent cc7674f7d7
commit 1077543b7c
27 changed files with 1952 additions and 192 deletions

View file

@ -73,6 +73,7 @@ using namespace std;
const string API_BASE = "https://api.unsandbox.com";
const string PORTAL_BASE = "https://unsandbox.com";
const int LANGUAGES_CACHE_TTL = 3600; // 1 hour in seconds
const string BLUE = "\033[34m";
const string RED = "\033[31m";
const string GREEN = "\033[32m";
@ -209,6 +210,79 @@ string build_env_content(const vector<string>& envs, const string& env_file) {
return parts.str();
}
string get_languages_cache_path() {
const char* home = getenv("HOME");
if (!home) home = ".";
return string(home) + "/.unsandbox/languages.json";
}
vector<string> load_languages_cache() {
vector<string> empty;
string cache_path = get_languages_cache_path();
struct stat st;
if (stat(cache_path.c_str(), &st) != 0) {
return empty; // File doesn't exist
}
// Check if cache is fresh (< 1 hour old)
time_t now = time(nullptr);
if (now - st.st_mtime >= LANGUAGES_CACHE_TTL) {
return empty; // Cache expired
}
string content = read_file(cache_path);
if (content.empty()) {
return empty;
}
// Parse languages from JSON {"languages": [...], "timestamp": ...}
vector<string> languages;
size_t pos = content.find("\"languages\":");
if (pos == string::npos) return empty;
pos = content.find('[', pos);
if (pos == string::npos) return empty;
pos++;
while (pos < content.length()) {
// Skip whitespace
while (pos < content.length() && (content[pos] == ' ' || content[pos] == '\n' || content[pos] == '\t')) pos++;
if (content[pos] == ']') break;
if (content[pos] == '"') {
pos++;
size_t end = content.find('"', pos);
if (end != string::npos) {
languages.push_back(content.substr(pos, end - pos));
pos = end + 1;
}
}
// Skip comma
while (pos < content.length() && (content[pos] == ',' || content[pos] == ' ' || content[pos] == '\n' || content[pos] == '\t')) pos++;
}
return languages;
}
void save_languages_cache(const vector<string>& languages) {
string cache_path = get_languages_cache_path();
// Create directory if needed
string dir = cache_path.substr(0, cache_path.rfind('/'));
mkdir(dir.c_str(), 0755);
ofstream f(cache_path);
if (!f) return;
f << "{\"languages\":[";
for (size_t i = 0; i < languages.size(); i++) {
if (i > 0) f << ",";
f << "\"" << languages[i] << "\"";
}
f << "],\"timestamp\":" << time(nullptr) << "}";
f.close();
}
string service_env_status(const string& service_id, const string& public_key, const string& secret_key) {
string path = "/services/" + service_id + "/env";
string auth_headers = build_auth_headers("GET", path, "", public_key, secret_key);
@ -695,13 +769,16 @@ void cmd_service(const string& name, const string& ports, const string& type, co
}
void cmd_languages(bool json_output, const string& public_key, const string& secret_key) {
string auth_headers = build_auth_headers("GET", "/languages", "", public_key, secret_key);
string cmd = "curl -s -X GET '" + API_BASE + "/languages' " + auth_headers;
string result = exec_curl(cmd);
// Try cache first
vector<string> names = load_languages_cache();
if (json_output) {
// Extract language names and output as JSON array
vector<string> names;
if (names.empty()) {
// Fetch from API
string auth_headers = build_auth_headers("GET", "/languages", "", public_key, secret_key);
string cmd = "curl -s -X GET '" + API_BASE + "/languages' " + auth_headers;
string result = exec_curl(cmd);
// Extract language names from response
size_t pos = 0;
string search = "\"name\":\"";
while ((pos = result.find(search, pos)) != string::npos) {
@ -712,6 +789,14 @@ void cmd_languages(bool json_output, const string& public_key, const string& sec
pos = end;
}
}
// Save to cache
if (!names.empty()) {
save_languages_cache(names);
}
}
if (json_output) {
cout << "[";
for (size_t i = 0; i < names.size(); i++) {
if (i > 0) cout << ",";
@ -720,15 +805,8 @@ void cmd_languages(bool json_output, const string& public_key, const string& sec
cout << "]" << endl;
} else {
// Output one language per line
size_t pos = 0;
string search = "\"name\":\"";
while ((pos = result.find(search, pos)) != string::npos) {
pos += search.length();
size_t end = result.find("\"", pos);
if (end != string::npos) {
cout << result.substr(pos, end - pos) << endl;
pos = end;
}
for (const auto& name : names) {
cout << name << endl;
}
}
}