std.cloud.gcp

Google Cloud Platform Bindings — 11 Units für Cloud Storage (GCS), Compute Engine (GCE), Cloud Firestore, Pub/Sub, Cloud Functions, Cloud Run, Cloud Logging, Cloud Monitoring, Secret Manager und IAM. Vollständig in Lyx implementiert, kein GCP SDK. Alle HTTPS-Anfragen laufen über std.net.tls; Authentifizierung über JWT RS256 (Service Accounts), OAuth 2.0 Refresh Token oder GCE-Metadata-Server.

Standard Library · std.cloud · std.crypto


Units im Überblick

Unit Import Beschreibung
std.cloud.gcp.credentials import std.cloud.gcp.credentials; Application Default Credentials: Credential Chain, Token-Cache, GCE-Erkennung (8 Fn)
std.cloud.gcp.jwt import std.cloud.gcp.jwt; JWT RS256 für Service Accounts: GCPServiceAccount, GCPBuildJWT, Base64url-Kodierung (5 Fn)
std.cloud.gcp.oauth import std.cloud.gcp.oauth; Access-Token-Verwaltung: GCPToken, auto-Refresh (Ablauf − 60 s), drei Token-Quellen (5 Fn)
std.cloud.gcp.transport import std.cloud.gcp.transport; HTTP-Transport: GCPClient, GCPResponse, GCPError, auto-Retry auf 429/5xx (10 Fn)
std.cloud.gcp.storage import std.cloud.gcp.storage; Cloud Storage (GCS): Buckets, Upload/Download, Metadaten, Listing (13 Fn)
std.cloud.gcp.compute import std.cloud.gcp.compute; Compute Engine (GCE): Instanzen, asynchrone Operationen, Standard-Zone europe-west1-b (10 Fn)
std.cloud.gcp.firestore import std.cloud.gcp.firestore; Cloud Firestore: FSDoc (max. 64 Felder), CRUD, Listing, JSON-Antwort (20 Fn)
std.cloud.gcp.pubsub import std.cloud.gcp.pubsub; Cloud Pub/Sub: Topics, Subscriptions, Publish, Pull, Acknowledge (10 Fn)
std.cloud.gcp.functions import std.cloud.gcp.functions; Cloud Functions v2 + Cloud Run v2: Deploy, Invoke, Service-Listing (12 Fn)
std.cloud.gcp.logging import std.cloud.gcp.logging; Cloud Logging + Cloud Monitoring: Text- und JSON-Logs, Custom Metrics, Alert Policies (10 Fn)
std.cloud.gcp.secrets import std.cloud.gcp.secrets; Secret Manager + IAM: Secret-CRUD, Versionierung, Service Accounts, IAM-Policies (15 Fn)

Architektur

┌───────────────────────────────────────────────────────────────────┐
│  Service-Units                                                     │
│  storage (GCS) · compute (GCE) · firestore · pubsub              │
│  functions (GCF + GCR) · logging (+ Monitoring) · secrets (+ IAM)│
├───────────────────────────────────────────────────────────────────┤
│  Interne GCP-Schichten                                             │
│  gcp/credentials  (Credential Chain, Token-Cache)                 │
│  gcp/jwt          (JWT RS256, GCPServiceAccount)                  │
│  gcp/oauth        (GCPToken, auto-Refresh)                        │
│  gcp/transport    (GCPClient, GCPResponse, Retry, Backoff)        │
├───────────────────────────────────────────────────────────────────┤
│  Netzwerk-Grundschicht                                             │
│  std.net.tls · std.net.http                                       │
└───────────────────────────────────────────────────────────────────┘


Credential-Chain

GCPCredentialsDefault durchsucht drei Quellen in dieser Reihenfolge:

  1. GOOGLE_APPLICATION_CREDENTIALS — Umgebungsvariable zeigt auf eine JSON-Datei (Service Account oder Authorized User)
  2. ADC-Datei~/.config/gcloud/application_default_credentials.json (nach gcloud auth application-default login)
  3. GCE-Metadata-Server — automatisch auf Google Compute Engine (metadata.google.internal)
Typ Konstante Authentifizierungsweg
Service Account GCP_CREDS_SERVICE_ACCOUNT (1) JSON-Datei → JWT RS256 → Bearer Token
Authorized User GCP_CREDS_REFRESH_TOKEN (2) JSON-Datei → OAuth 2.0 Refresh → Bearer Token
GCE-Metadata GCP_CREDS_METADATA (3) GCE-Metadata-Server → Bearer Token

Der Token wird im GCPCredentials-Struct gecacht und automatisch erneuert, sobald er weniger als 60 Sekunden gültig ist.

import std.cloud.gcp.credentials;
import std.cloud.gcp.storage;

fn main(): int64 {
    // Credential Chain: env → ADC → GCE-Metadata
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/cloud-platform"c);

    var gcs: GCSConn := GCSConnect(addr creds, "mein-projekt"c);

    var data: pchar := "Hello GCS"c;
    GCSUpload(gcs, "mein-bucket"c, "hello.txt"c, data as int64, 9, "text/plain"c);

    GCSDisconnect(gcs);
    GCPCredentialsFree(creds);
    return 0;
}


Transport & Fehlerbehandlung

Alle Service-Funktionen geben GCPResponse zurück:

Feld Typ Beschreibung
statusCode int64 HTTP-Statuscode (200, 404, 429 …)
body int64 Zeiger auf allokierten Antwort-Body (oder 0)
bodyLen int64 Länge des Body in Bytes
contentType int64 Content-Type-Header-Wert (pchar oder 0)

GCPResponseFree® gibt body und contentType frei.

Konstante Wert Bedeutung
GCP_ERR_OK 0 Erfolg
GCP_ERR_AUTH 401 Authentifizierung fehlgeschlagen
GCP_ERR_FORBIDDEN 403 Zugriff verweigert
GCP_ERR_NOT_FOUND 404 Ressource nicht gefunden
GCP_ERR_CONFLICT 409 Ressource existiert bereits
GCP_ERR_RATE_LIMIT 429 Zu viele Anfragen
GCP_ERR_SERVER 500 Server-Fehler

Der Transport-Layer wiederholt Anfragen bei 429, 500, 502, 503 und 504 automatisch — bis zu 3 Mal, mit exponentiellem Backoff (100 ms × 2ⁿ). User-Agent: lyxgcloud/1.0.


Cloud Storage (GCS)

API: storage.googleapis.com · Pfad: /storage/v1/b/{bucket}/o/{object}

Funktion Signatur Beschreibung
GCSConnect (credsPtr, project) → GCSConn Verbindung zur Storage API
GCSDisconnect © Ressourcen freigeben
GCSBucketCreate (c, bucket, location) → int64 Bucket anlegen; location Standard: „US“
GCSBucketDelete (c, bucket) → int64 Bucket löschen
GCSBucketExists (c, bucket) → int64 1 = vorhanden
GCSUpload (c, bucket, object, data, dataLen, contentType) → int64 Objekt hochladen
GCSUploadJSON (c, bucket, object, json, jsonLen) → int64 JSON-Objekt hochladen
GCSDownload (c, bucket, object) → GCPResponse Objekt herunterladen; Caller gibt r via GCPResponseFree frei
GCSDownloadRange (c, bucket, object, start, end) → GCPResponse Teilbereich; TODO: Range-Header noch nicht implementiert
GCSDelete (c, bucket, object) → int64 Objekt löschen
GCSExists (c, bucket, object) → int64 1 = vorhanden
GCSGetMeta (c, bucket, object) → GCPResponse Objekt-Metadaten als JSON
GCSList (c, bucket, prefix, pageSize) → GCPResponse Objekte auflisten (paginiert)

import std.cloud.gcp.credentials;
import std.cloud.gcp.storage;

fn main(): int64 {
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/devstorage.read_write"c);
    var gcs: GCSConn := GCSConnect(addr creds, "mein-projekt"c);

    // Datei hochladen
    var data: pchar := "Hallo Welt"c;
    GCSUpload(gcs, "mein-bucket"c, "test.txt"c, data as int64, 10, "text/plain"c);

    // Datei herunterladen
    var r: GCPResponse := GCSDownload(gcs, "mein-bucket"c, "test.txt"c);
    if (r.statusCode == 200) {
        Print(r.body as pchar); PrintLn(""c);
    }
    GCPResponseFree(r);

    GCSDisconnect(gcs);
    GCPCredentialsFree(creds);
    return 0;
}


Compute Engine (GCE)

API: compute.googleapis.com · Standard-Zone: europe-west1-b

Asynchrone Operationen (Erstellen, Löschen, Starten, Stoppen) geben GCEOperation zurück. GCEOperationWait pollt alle 2 Sekunden, maximal 30 Versuche (60 Sekunden gesamt).

Funktion Signatur Beschreibung
GCEConnect (credsPtr, project, zone) → GCEConn Verbindung; zone = 0 → europe-west1-b
GCEDisconnect © Ressourcen freigeben
GCEInstanceCreate (c, name, machineType, image, diskSizeGB) → GCEOperation VM anlegen (asynchron)
GCEInstanceDelete (c, name) → GCEOperation VM löschen (asynchron)
GCEInstanceStart (c, name) → GCEOperation VM starten (asynchron)
GCEInstanceStop (c, name) → GCEOperation VM stoppen (asynchron)
GCEInstanceGet (c, name) → int64 VM-Details als JSON-pchar (Caller frees)
GCEInstanceList © → GCPResponse Alle VMs in der Zone auflisten
GCEOperationWait (c, op) → GCEOperation Warten bis done = 1 (max. 60 s)
GCEOperationFree (op) GCEOperation-Ressourcen freigeben

import std.cloud.gcp.credentials;
import std.cloud.gcp.compute;

fn main(): int64 {
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/compute"c);
    var gce: GCEConn := GCEConnect(addr creds, "mein-projekt"c, "europe-west1-b"c);

    var op: GCEOperation := GCEInstanceCreate(gce, "web-01"c, "e2-micro"c,
        "projects/debian-cloud/global/images/debian-12-bookworm-v20250101"c, 20);
    op = GCEOperationWait(gce, op);
    if (op.done == 1) {
        PrintLn("VM bereit"c);
    }
    GCEOperationFree(op);

    GCEDisconnect(gce);
    GCPCredentialsFree(creds);
    return 0;
}


Cloud Firestore

API: firestore.googleapis.com · Standard-Datenbank: (default)

Dokumente werden über FSDoc verwaltet (max. 64 Felder). Unterstützte Feldtypen: String, Int64, Bool, Null.

Typ Beschreibung
FirestoreConn Verbindungskontext (client, project, database)
FSDoc Dokument-Handle; intern verwaltet Feldname + Wert + Typ
Feldtyp-Konstante Wert
FS_TYPE_STRING 1
FS_TYPE_INT 2
FS_TYPE_BOOL 3
FS_TYPE_NULL 4
Funktion Signatur Beschreibung
FSDocNew () → int64 Leeres Dokument anlegen
FSDocFree (doc) Dokument freigeben
FSDocSetString (doc, key, value) String-Feld setzen
FSDocSetInt (doc, key, value) Int64-Feld setzen
FSDocSetBool (doc, key, value) Bool-Feld setzen
FSDocGetString (doc, key) → pchar String-Wert lesen (oder 0)
FSDocGetInt (doc, key) → int64 Int-Wert lesen (oder 0)
FSDocHasField (doc, key) → int64 1 = Feld vorhanden
FSDocFieldCount (doc) → int64 Anzahl der Felder
FSDocToJSON (doc) → int64 Firestore-REST-JSON erzeugen (Caller frees via FSDocFreeJSON)
FirestoreConnect (credsPtr, project, database) → FirestoreConn Verbindung aufbauen
FirestoreDisconnect © Ressourcen freigeben
FSCreate (c, collection, docId, doc) → int64 Dokument anlegen
FSGet (c, collection, docId) → int64 Dokument lesen → FSDoc mit Roh-JSON im Feld „json“
FSUpdate (c, collection, docId, doc) → int64 Dokument aktualisieren (PATCH)
FSSet (c, collection, docId, doc) → int64 Alias für FSCreate
FSDelete (c, collection, docId) → int64 Dokument löschen
FSExists (c, collection, docId) → int64 1 = Dokument vorhanden
FSList (c, collection, pageSize) → GCPResponse Alle Dokumente einer Collection

Hinweis zu FSGet: Das zurückgegebene FSDoc enthält das Feld „json“ mit dem Roh-JSON-Body der Firestore REST-Antwort. Ein vollständiger Firestore-Value-Type-Parser (stringValue, integerValue …) ist nicht implementiert — bei Bedarf muss der JSON-Body selbst ausgewertet werden.

import std.cloud.gcp.credentials;
import std.cloud.gcp.firestore;

fn main(): int64 {
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/datastore"c);
    var fs: FirestoreConn := FirestoreConnect(addr creds, "mein-projekt"c, "(default)"c);

    var doc: int64 := FSDocNew();
    FSDocSetString(doc, "name"c, "Andreas"c);
    FSDocSetInt(doc, "version"c, 1);
    FSDocSetBool(doc, "aktiv"c, 1);
    FSCreate(fs, "users"c, "user-1"c, doc);
    FSDocFree(doc);

    FirestoreDisconnect(fs);
    GCPCredentialsFree(creds);
    return 0;
}


Cloud Pub/Sub

API: pubsub.googleapis.com · Ressourcen-Format: projects/{project}/topics/{topic}

Nachrichten-Payload wird beim Publishen automatisch als Base64url kodiert. PubSubAck erwartet ein int64*-Array von pchar-Zeigern (die ackId-Strings aus der Pull-Antwort).

Funktion Signatur Beschreibung
PubSubConnect (credsPtr, project) → PubSubConn Verbindung zur Pub/Sub API
PubSubDisconnect © Ressourcen freigeben
PubSubTopicCreate (c, topic) → int64 Topic anlegen
PubSubTopicDelete (c, topic) → int64 Topic löschen
PubSubTopicExists (c, topic) → int64 1 = vorhanden
PubSubSubscriptionCreate (c, sub, topic, ackDeadline) → int64 Subscription anlegen; ackDeadline ≤ 0 → 30 s
PubSubSubscriptionDelete (c, sub) → int64 Subscription löschen
PubSubPublish (c, topic, data, dataLen) → GCPResponse Nachricht publishen (base64url-kodiert)
PubSubPull (c, sub, maxMessages) → GCPResponse Nachrichten abrufen; ≤ 0 → max. 10
PubSubAck (c, sub, ackIds, ackIdCount) → int64 Nachrichten bestätigen

import std.cloud.gcp.credentials;
import std.cloud.gcp.pubsub;

fn main(): int64 {
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/pubsub"c);
    var ps: PubSubConn := PubSubConnect(addr creds, "mein-projekt"c);

    PubSubTopicCreate(ps, "events"c);
    PubSubSubscriptionCreate(ps, "events-sub"c, "events"c, 60);

    var msg: pchar := "Ereignis eingetreten"c;
    var r: GCPResponse := PubSubPublish(ps, "events"c, msg as int64, 20);
    GCPResponseFree(r);

    PubSubDisconnect(ps);
    GCPCredentialsFree(creds);
    return 0;
}


Cloud Functions & Cloud Run

Beide Dienste nutzen dieselbe Region-Konfiguration. Standard-Region: europe-west1.

Cloud Functions v2: API cloudfunctions.googleapis.com · Pfad /v2/projects/{proj}/locations/{region}/functions

Cloud Run v2: API run.googleapis.com · Pfad /v2/projects/{proj}/locations/{region}/services

Hinweis: GCRServiceInvoke ist ein Platzhalter (gibt HTTP 501 zurück). Cloud Run Services werden über ihre eigene Service-URL aufgerufen — dafür direkt std.net.https mit Bearer-Token aus GCPGetToken verwenden.

Funktion Typ Beschreibung
GCFConnect GCFConn Verbindung zu Cloud Functions v2
GCFDisconnect Ressourcen freigeben
GCFList → GCPResponse Alle Functions in der Region auflisten
GCFGet → GCPResponse Eine Function abrufen
GCFDelete → int64 Function löschen
GCFDeploy → GCPResponse Function deployen (runtime, entryPoint, GCS-Source „bucket/path.zip“)
GCFInvoke → GCPResponse Function aufrufen (POST …:call)
GCRConnect GCRConn Verbindung zu Cloud Run v2
GCRDisconnect Ressourcen freigeben
GCRServiceList → GCPResponse Alle Cloud Run Services auflisten
GCRServiceGet → GCPResponse Einen Cloud Run Service abrufen
GCRServiceInvoke → GCPResponse Platzhalter — gibt HTTP 501 zurück

import std.cloud.gcp.credentials;
import std.cloud.gcp.functions;

fn main(): int64 {
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/cloud-platform"c);
    var gcf: GCFConn := GCFConnect(addr creds, "mein-projekt"c, "europe-west1"c);

    // Cloud Function deployen (Quellcode als ZIP in GCS)
    var r: GCPResponse := GCFDeploy(gcf, "helloWorld"c, "nodejs20"c,
                                    "helloWorld"c, "mein-bucket/function.zip"c);
    GCPResponseFree(r);

    // Function aufrufen
    var body: pchar := "{\"name\":\"Lyx\"}"c;
    var res: GCPResponse := GCFInvoke(gcf, "helloWorld"c, body as int64, 14);
    if (res.statusCode == 200) {
        Print(res.body as pchar); PrintLn(""c);
    }
    GCPResponseFree(res);

    GCFDisconnect(gcf);
    GCPCredentialsFree(creds);
    return 0;
}


Cloud Logging & Cloud Monitoring

Logging: API logging.googleapis.com · Endpunkt POST /v2/entries:write

Log-Einträge werden mit resource.type=„global“ erstellt. Der vollständige Log-Name wird automatisch aus projects/{project}/logs/{logName} zusammengebaut.

Schweregrad-Konstante Wert Syslog-Äquivalent
LOG_DEFAULT 0
LOG_DEBUG 100 DEBUG
LOG_INFO 200 INFO
LOG_NOTICE 300 NOTICE
LOG_WARNING 400 WARNING
LOG_ERROR 500 ERROR
LOG_CRITICAL 600 CRITICAL
LOG_ALERT 700 ALERT
LOG_EMERGENCY 800 EMERGENCY
Funktion Signatur Beschreibung
LogConnect (credsPtr, project) → LogConn Verbindung zur Logging API
LogDisconnect © Ressourcen freigeben
LogWrite (c, logName, severity, message) → int64 Text-Log-Eintrag schreiben
LogWriteJSON (c, logName, severity, jsonPayload, jsonLen) → int64 Strukturierten JSON-Log schreiben
LogList (c, logName, filter, pageSize) → GCPResponse Log-Einträge lesen (pageSize ≤ 0 → 100)

Monitoring: API monitoring.googleapis.com · Endpunkt POST /v3/projects/{project}/timeSeries

MonWriteMetric schreibt einen Integer-Gauge-Wert als Custom Metric Time Series. metricType muss mit custom.googleapis.com/ beginnen.

Funktion Signatur Beschreibung
MonConnect (credsPtr, project) → MonConn Verbindung zur Monitoring API
MonDisconnect © Ressourcen freigeben
MonWriteMetric (c, metricType, value, labels) → int64 Gauge-Wert schreiben; labels = JSON-Objekt oder 0
MonListMetrics (c, filter) → GCPResponse Time Series auflisten
MonCreateAlertPolicy (c, policy, policyLen) → int64 Alert Policy anlegen (JSON-Body)

import std.cloud.gcp.credentials;
import std.cloud.gcp.logging;

fn main(): int64 {
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/logging.write"c);
    var log: LogConn := LogConnect(addr creds, "mein-projekt"c);

    LogWrite(log, "app-log"c, LOG_INFO, "Anwendung gestartet"c);

    var json: pchar := "{\"event\":\"startup\",\"version\":2}"c;
    LogWriteJSON(log, "app-log"c, LOG_INFO, json as int64, 30);

    var mon: MonConn := MonConnect(addr creds, "mein-projekt"c);
    MonWriteMetric(mon, "custom.googleapis.com/anfragen_pro_sekunde"c, 42, 0);

    MonDisconnect(mon);
    LogDisconnect(log);
    GCPCredentialsFree(creds);
    return 0;
}


Secret Manager & IAM

Secret Manager: API secretmanager.googleapis.com · Pfad /v1/projects/{project}/secrets

Secrets werden base64url-kodiert gespeichert. SecretCreate führt zwei API-Aufrufe durch: Zuerst wird das Secret angelegt (automatische Replikation), dann wird die erste Version mit dem Payload hinzugefügt.

SecretGetLatest und SecretGet dekodieren den Payload automatisch und geben einen allokierten pchar zurück (Caller frees mit free(val, StrLen(val) + 1)).

IAM: API iam.googleapis.com · Pfad /v1/projects/{project}/serviceAccounts

Funktion Signatur Beschreibung
SecretConnect (credsPtr, project) → SecretConn Verbindung zu Secret Manager
SecretDisconnect © Ressourcen freigeben
SecretCreate (c, name, payload, payloadLen) → int64 Secret anlegen + erste Version speichern (2 API-Aufrufe)
SecretGet (c, name) → int64 Neueste Version abrufen und dekodieren (= SecretGetLatest)
SecretGetLatest (c, name) → int64 Neueste Version abrufen und base64url-dekodieren (Caller frees)
SecretAddVersion (c, name, payload, payloadLen) → int64 Neue Version zu bestehendem Secret hinzufügen
SecretList © → GCPResponse Alle Secrets auflisten
SecretDelete (c, name) → int64 Secret löschen
IAMConnect (credsPtr, project) → IAMConn Verbindung zu IAM
IAMDisconnect © Ressourcen freigeben
IAMListServiceAccounts © → GCPResponse Alle Service Accounts auflisten
IAMCreateServiceAccount (c, accountId, displayName) → int64 Service Account anlegen
IAMDeleteServiceAccount (c, email) → int64 Service Account löschen (via E-Mail)
IAMGetIAMPolicy (c, resource) → GCPResponse IAM-Policy einer Ressource abrufen
IAMSetIAMPolicy (c, resource, policy, policyLen) → int64 IAM-Policy setzen

import std.cloud.gcp.credentials;
import std.cloud.gcp.secrets;
import std.alloc;

fn main(): int64 {
    var creds: GCPCredentials := GCPCredentialsDefault(
        "https://www.googleapis.com/auth/cloud-platform"c);
    var sc: SecretConn := SecretConnect(addr creds, "mein-projekt"c);

    // Secret anlegen (Payload wird base64url-kodiert gespeichert)
    var payload: pchar := "geheimes-passwort-123"c;
    SecretCreate(sc, "db-password"c, payload as int64, 21);

    // Secret auslesen (automatisch dekodiert)
    var val: int64 := SecretGet(sc, "db-password"c);
    if (val != 0) {
        Print(val as pchar); PrintLn(""c);
        free(val, StrLen(val as pchar) + 1);
    }

    SecretDisconnect(sc);
    GCPCredentialsFree(creds);
    return 0;
}


Letzte Aktualisierung: 2026-06-13