1package soju
2
3import (
4	"context"
5	"fmt"
6	"net/url"
7	"strings"
8	"time"
9
10	"github.com/prometheus/client_golang/prometheus"
11)
12
13type Database interface {
14	Close() error
15	Stats(ctx context.Context) (*DatabaseStats, error)
16
17	ListUsers(ctx context.Context) ([]User, error)
18	GetUser(ctx context.Context, username string) (*User, error)
19	StoreUser(ctx context.Context, user *User) error
20	DeleteUser(ctx context.Context, id int64) error
21
22	ListNetworks(ctx context.Context, userID int64) ([]Network, error)
23	StoreNetwork(ctx context.Context, userID int64, network *Network) error
24	DeleteNetwork(ctx context.Context, id int64) error
25	ListChannels(ctx context.Context, networkID int64) ([]Channel, error)
26	StoreChannel(ctx context.Context, networKID int64, ch *Channel) error
27	DeleteChannel(ctx context.Context, id int64) error
28
29	ListDeliveryReceipts(ctx context.Context, networkID int64) ([]DeliveryReceipt, error)
30	StoreClientDeliveryReceipts(ctx context.Context, networkID int64, client string, receipts []DeliveryReceipt) error
31}
32
33type MetricsCollectorDatabase interface {
34	Database
35	MetricsCollector() prometheus.Collector
36}
37
38func OpenDB(driver, source string) (Database, error) {
39	switch driver {
40	case "sqlite3":
41		return OpenSqliteDB(source)
42	case "postgres":
43		return OpenPostgresDB(source)
44	default:
45		return nil, fmt.Errorf("unsupported database driver: %q", driver)
46	}
47}
48
49type DatabaseStats struct {
50	Users    int64
51	Networks int64
52	Channels int64
53}
54
55type User struct {
56	ID       int64
57	Username string
58	Password string // hashed
59	Realname string
60	Admin    bool
61}
62
63type SASL struct {
64	Mechanism string
65
66	Plain struct {
67		Username string
68		Password string
69	}
70
71	// TLS client certificate authentication.
72	External struct {
73		// X.509 certificate in DER form.
74		CertBlob []byte
75		// PKCS#8 private key in DER form.
76		PrivKeyBlob []byte
77	}
78}
79
80type Network struct {
81	ID              int64
82	Name            string
83	Addr            string
84	Nick            string
85	Username        string
86	Realname        string
87	Pass            string
88	ConnectCommands []string
89	SASL            SASL
90	Enabled         bool
91}
92
93func (net *Network) GetName() string {
94	if net.Name != "" {
95		return net.Name
96	}
97	return net.Addr
98}
99
100func (net *Network) URL() (*url.URL, error) {
101	s := net.Addr
102	if !strings.Contains(s, "://") {
103		// This is a raw domain name, make it an URL with the default scheme
104		s = "ircs://" + s
105	}
106
107	u, err := url.Parse(s)
108	if err != nil {
109		return nil, fmt.Errorf("failed to parse upstream server URL: %v", err)
110	}
111
112	return u, nil
113}
114
115func GetNick(user *User, net *Network) string {
116	if net.Nick != "" {
117		return net.Nick
118	}
119	return user.Username
120}
121
122func GetUsername(user *User, net *Network) string {
123	if net.Username != "" {
124		return net.Username
125	}
126	return GetNick(user, net)
127}
128
129func GetRealname(user *User, net *Network) string {
130	if net.Realname != "" {
131		return net.Realname
132	}
133	if user.Realname != "" {
134		return user.Realname
135	}
136	return GetNick(user, net)
137}
138
139type MessageFilter int
140
141const (
142	// TODO: use customizable user defaults for FilterDefault
143	FilterDefault MessageFilter = iota
144	FilterNone
145	FilterHighlight
146	FilterMessage
147)
148
149func parseFilter(filter string) (MessageFilter, error) {
150	switch filter {
151	case "default":
152		return FilterDefault, nil
153	case "none":
154		return FilterNone, nil
155	case "highlight":
156		return FilterHighlight, nil
157	case "message":
158		return FilterMessage, nil
159	}
160	return 0, fmt.Errorf("unknown filter: %q", filter)
161}
162
163type Channel struct {
164	ID   int64
165	Name string
166	Key  string
167
168	Detached              bool
169	DetachedInternalMsgID string
170
171	RelayDetached MessageFilter
172	ReattachOn    MessageFilter
173	DetachAfter   time.Duration
174	DetachOn      MessageFilter
175}
176
177type DeliveryReceipt struct {
178	ID            int64
179	Target        string // channel or nick
180	Client        string
181	InternalMsgID string
182}
183