mirror of
https://github.com/DeBrosOfficial/network.git
synced 2026-01-30 06:53:03 +00:00
206 lines
5.4 KiB
Go
206 lines
5.4 KiB
Go
package node
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/DeBrosOfficial/network/pkg/gateway"
|
|
"github.com/DeBrosOfficial/network/pkg/ipfs"
|
|
"github.com/DeBrosOfficial/network/pkg/logging"
|
|
"golang.org/x/crypto/acme"
|
|
"golang.org/x/crypto/acme/autocert"
|
|
)
|
|
|
|
// startHTTPGateway initializes and starts the full API gateway
|
|
func (n *Node) startHTTPGateway(ctx context.Context) error {
|
|
if !n.config.HTTPGateway.Enabled {
|
|
n.logger.ComponentInfo(logging.ComponentNode, "HTTP Gateway disabled in config")
|
|
return nil
|
|
}
|
|
|
|
logFile := filepath.Join(os.ExpandEnv(n.config.Node.DataDir), "..", "logs", "gateway.log")
|
|
logsDir := filepath.Dir(logFile)
|
|
_ = os.MkdirAll(logsDir, 0755)
|
|
|
|
gatewayLogger, err := logging.NewFileLogger(logging.ComponentGeneral, logFile, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
gwCfg := &gateway.Config{
|
|
ListenAddr: n.config.HTTPGateway.ListenAddr,
|
|
ClientNamespace: n.config.HTTPGateway.ClientNamespace,
|
|
BootstrapPeers: n.config.Discovery.BootstrapPeers,
|
|
NodePeerID: loadNodePeerIDFromIdentity(n.config.Node.DataDir),
|
|
RQLiteDSN: n.config.HTTPGateway.RQLiteDSN,
|
|
OlricServers: n.config.HTTPGateway.OlricServers,
|
|
OlricTimeout: n.config.HTTPGateway.OlricTimeout,
|
|
IPFSClusterAPIURL: n.config.HTTPGateway.IPFSClusterAPIURL,
|
|
IPFSAPIURL: n.config.HTTPGateway.IPFSAPIURL,
|
|
IPFSTimeout: n.config.HTTPGateway.IPFSTimeout,
|
|
EnableHTTPS: n.config.HTTPGateway.HTTPS.Enabled,
|
|
DomainName: n.config.HTTPGateway.HTTPS.Domain,
|
|
TLSCacheDir: n.config.HTTPGateway.HTTPS.CacheDir,
|
|
BaseDomain: n.config.HTTPGateway.BaseDomain,
|
|
}
|
|
|
|
apiGateway, err := gateway.New(gatewayLogger, gwCfg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
n.apiGateway = apiGateway
|
|
|
|
var certManager *autocert.Manager
|
|
if gwCfg.EnableHTTPS && gwCfg.DomainName != "" {
|
|
tlsCacheDir := gwCfg.TLSCacheDir
|
|
if tlsCacheDir == "" {
|
|
tlsCacheDir = "/home/debros/.orama/tls-cache"
|
|
}
|
|
_ = os.MkdirAll(tlsCacheDir, 0700)
|
|
|
|
certManager = &autocert.Manager{
|
|
Prompt: autocert.AcceptTOS,
|
|
HostPolicy: autocert.HostWhitelist(gwCfg.DomainName),
|
|
Cache: autocert.DirCache(tlsCacheDir),
|
|
Email: fmt.Sprintf("admin@%s", gwCfg.DomainName),
|
|
Client: &acme.Client{
|
|
DirectoryURL: "https://acme-staging-v02.api.letsencrypt.org/directory",
|
|
},
|
|
}
|
|
n.certManager = certManager
|
|
n.certReady = make(chan struct{})
|
|
}
|
|
|
|
httpReady := make(chan struct{})
|
|
|
|
go func() {
|
|
if gwCfg.EnableHTTPS && gwCfg.DomainName != "" && certManager != nil {
|
|
httpsPort := 443
|
|
httpPort := 80
|
|
|
|
httpServer := &http.Server{
|
|
Addr: fmt.Sprintf(":%d", httpPort),
|
|
Handler: certManager.HTTPHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
target := fmt.Sprintf("https://%s%s", r.Host, r.URL.RequestURI())
|
|
http.Redirect(w, r, target, http.StatusMovedPermanently)
|
|
})),
|
|
}
|
|
|
|
httpListener, err := net.Listen("tcp", fmt.Sprintf(":%d", httpPort))
|
|
if err != nil {
|
|
close(httpReady)
|
|
return
|
|
}
|
|
|
|
go httpServer.Serve(httpListener)
|
|
|
|
// Pre-provision cert
|
|
certReq := &tls.ClientHelloInfo{ServerName: gwCfg.DomainName}
|
|
_, certErr := certManager.GetCertificate(certReq)
|
|
|
|
if certErr != nil {
|
|
close(httpReady)
|
|
httpServer.Handler = apiGateway.Routes()
|
|
return
|
|
}
|
|
|
|
close(httpReady)
|
|
|
|
tlsConfig := &tls.Config{
|
|
MinVersion: tls.VersionTLS12,
|
|
GetCertificate: certManager.GetCertificate,
|
|
}
|
|
|
|
httpsServer := &http.Server{
|
|
Addr: fmt.Sprintf(":%d", httpsPort),
|
|
TLSConfig: tlsConfig,
|
|
Handler: apiGateway.Routes(),
|
|
}
|
|
n.apiGatewayServer = httpsServer
|
|
|
|
ln, err := tls.Listen("tcp", fmt.Sprintf(":%d", httpsPort), tlsConfig)
|
|
if err == nil {
|
|
httpsServer.Serve(ln)
|
|
}
|
|
} else {
|
|
close(httpReady)
|
|
server := &http.Server{
|
|
Addr: gwCfg.ListenAddr,
|
|
Handler: apiGateway.Routes(),
|
|
}
|
|
n.apiGatewayServer = server
|
|
ln, err := net.Listen("tcp", gwCfg.ListenAddr)
|
|
if err == nil {
|
|
server.Serve(ln)
|
|
}
|
|
}
|
|
}()
|
|
|
|
// SNI Gateway
|
|
if n.config.HTTPGateway.SNI.Enabled && n.certManager != nil {
|
|
go n.startSNIGateway(ctx, httpReady)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (n *Node) startSNIGateway(ctx context.Context, httpReady <-chan struct{}) {
|
|
<-httpReady
|
|
domain := n.config.HTTPGateway.HTTPS.Domain
|
|
if domain == "" {
|
|
return
|
|
}
|
|
|
|
certReq := &tls.ClientHelloInfo{ServerName: domain}
|
|
tlsCert, err := n.certManager.GetCertificate(certReq)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
tlsCacheDir := n.config.HTTPGateway.HTTPS.CacheDir
|
|
if tlsCacheDir == "" {
|
|
tlsCacheDir = "/home/debros/.orama/tls-cache"
|
|
}
|
|
|
|
certPath := filepath.Join(tlsCacheDir, domain+".crt")
|
|
keyPath := filepath.Join(tlsCacheDir, domain+".key")
|
|
|
|
if err := extractPEMFromTLSCert(tlsCert, certPath, keyPath); err == nil {
|
|
if n.certReady != nil {
|
|
close(n.certReady)
|
|
}
|
|
}
|
|
|
|
sniCfg := n.config.HTTPGateway.SNI
|
|
sniGateway, err := gateway.NewTCPSNIGateway(n.logger, &sniCfg)
|
|
if err == nil {
|
|
n.sniGateway = sniGateway
|
|
sniGateway.Start(ctx)
|
|
}
|
|
}
|
|
|
|
// startIPFSClusterConfig initializes and ensures IPFS Cluster configuration
|
|
func (n *Node) startIPFSClusterConfig() error {
|
|
n.logger.ComponentInfo(logging.ComponentNode, "Initializing IPFS Cluster configuration")
|
|
|
|
cm, err := ipfs.NewClusterConfigManager(n.config, n.logger.Logger)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
n.clusterConfigManager = cm
|
|
|
|
_ = cm.FixIPFSConfigAddresses()
|
|
if err := cm.EnsureConfig(); err != nil {
|
|
return err
|
|
}
|
|
|
|
_ = cm.RepairPeerConfiguration()
|
|
return nil
|
|
}
|
|
|