🏡 index : quine-global-labs/quple.git

// Command quple-server is the central rendezvous service for Quple
// (meet.quineglobal.com).
//
// Everyone signs in with Quine (identity.quineglobal.com), the one identity
// server, and is known by their Quine username. Signed-in clients announce
// themselves, keep a contact list, place calls, and poll for calls placed to
// them. A call names the Jitsi Meet server it happens on - any one, picked by
// the caller - and this server just tells the callee where to go. The meeting
// itself (media, chat, etc.) happens entirely inside Jitsi Meet, which this
// server never talks to.
//
// Configuration (environment):
//
//	ADDR           listen address (default :8080)
//	ISSUER         Quine identity server whose access tokens are accepted
//	               (default https://identity.quineglobal.com)
//	CLIENT_ID      app the tokens must be issued to (default quple)
//	DEFAULT_JITSI  Jitsi Meet server for calls that don't name one (default https://meet.jit.si)
//	DATA_DIR       contacts (default ./data)
package main

import (
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func main() {
	addr := envOr("ADDR", ":8080")
	issuer := envOr("ISSUER", "https://identity.quineglobal.com")
	dataDir := envOr("DATA_DIR", "data")
	defaultJitsi, err := normalizeJitsiURL(envOr("DEFAULT_JITSI", "https://meet.jit.si"))
	if err != nil {
		log.Fatalf("DEFAULT_JITSI: %v", err)
	}

	if err := os.MkdirAll(dataDir, 0o700); err != nil {
		log.Fatal(err)
	}
	contacts, err := LoadContacts(filepath.Join(dataDir, "contacts.json"))
	if err != nil {
		log.Fatal(err)
	}

	app := &App{
		verifier:        NewVerifier(issuer, envOr("CLIENT_ID", "quple")),
		store:           NewStore(),
		contacts:        contacts,
		defaultJitsiURL: defaultJitsi,
	}
	mux := http.NewServeMux()
	app.Routes(mux)
	mux.HandleFunc("/healthz", withCORS(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ok"))
	}))

	log.Printf("quple-server listening on %s, accepting tokens from %s, default Jitsi %s", addr, issuer, defaultJitsi)
	log.Fatal(http.ListenAndServe(addr, mux))
}

func envOr(key, fallback string) string {
	if v := os.Getenv(key); v != "" {
		return v
	}
	return fallback
}