← history for internal/tlsclient/tlsclient.go
b71576d2internal/tlsclient/tlsclient.go124 lines⬡ raw↓ download
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
 * RemoteBrain - rbrain
 *
 * This file is licensed under the Affero General Public License version 3 or
 * later. See the COPYING file.
 *
 * @author Paolo Lulli <kevwe.com>
 * @copyright Paolo Lulli 2026
 */

package tlsclient

import (
    "bytes"
    "crypto/tls"
    "database/sql"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "path"
    "rbrain/internal/config"
    "rbrain/internal/ollama"
    "rbrain/internal/queries"
    "rbrain/internal/service"
)

type RBrain struct {
    Config config.RemoteChatConfiguration
}

func (c *RBrain) secureHttpClient(key string, cert string) (client *http.Client) {
    x509cert, err := tls.LoadX509KeyPair(cert, key)

    if err != nil {
        fmt.Printf("Error loading X509 certificate: %s and/or key: %s", cert, key)
        panic(err.Error())
    }
    certs := []tls.Certificate{x509cert}
    if len(certs) == 0 {
        client = &http.Client{}
        return
    }

    insecureSkipVerify := false
    if c.Config.TlsVerifyServer == "false" {
        insecureSkipVerify = true
    }

    tr := &http.Transport{
        TLSClientConfig: &tls.Config{Certificates: certs,
            InsecureSkipVerify: insecureSkipVerify},
    }
    client = &http.Client{Transport: tr}
    return
}

func (c *RBrain) ApiPost(endpoint string, body string) string {
    var client *http.Client
    if c.Config.Insecure == "true" {
        client = &http.Client{}
    } else {
        cert := path.Join(c.Config.TlsCertificate)
        certKey := path.Join(c.Config.TlsKeyFile)
        client = c.secureHttpClient(certKey, cert)
    }
    req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer([]byte(body)))
    req.Header.Set("Content-Type", "application/json; charset=UTF-8")
    if err != nil {
        fmt.Println("Unable to make POST request", err)
        os.Exit(1)
    }
    req.Header.Add("Accept", "* / *")
    resp, err := client.Do(req)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }

    var r ollama.OllamaResponse
    if err := json.NewDecoder(resp.Body).Decode(&r); err != nil {
        return ""
    }

    defer resp.Body.Close()
    return r.Response
}

func (c *RBrain) CallOllama(prompt, model string) (string, error) {
    payload, _ := json.Marshal(ollama.OllamaRequest{
        Model:  model,
        Prompt: prompt,
        Stream: false,
    })

    resp := c.ApiPost(c.Config.Endpoint, bytes.NewBuffer(payload).String())

    return resp, nil
}

// processMessage saves the request, calls Ollama, and saves the response —
// all in a separate goroutine. It sends a single result on ch when done.
func (c *RBrain) ProcessMessage(db *sql.DB, message, model string, ch chan<- service.Result) {
    go func() {
        requestID, err := queries.SaveRequest(db, message)
        if err != nil {
            ch <- service.Result{Err: err}
            return
        }

        response, err := c.CallOllama(message, model)
        if err != nil {
            ch <- service.Result{Err: err}
            return
        }

        if err := queries.SaveResponse(db, requestID, response); err != nil {
            ch <- service.Result{Err: err}
            return
        }

        ch <- service.Result{Text: response}
    }()
}