Implement basic matrix client
This commit is contained in:
parent
8dd0a1f3be
commit
f8479ed7b6
|
@ -8,6 +8,8 @@ steps:
|
|||
- name: build
|
||||
image: golang
|
||||
commands:
|
||||
- apt-get update
|
||||
- apt-get install -y libolm-dev
|
||||
- go build -ldflags="-s -w" -o matrix-pretix .
|
||||
|
||||
- name: release
|
||||
|
|
13
go.mod
13
go.mod
|
@ -2,9 +2,20 @@ module git.luj0ga.de/franconian/matrix-pretix
|
|||
|
||||
go 1.18
|
||||
|
||||
require maunium.net/go/mautrix v0.11.0
|
||||
require (
|
||||
github.com/mattn/go-sqlite3 v1.14.13
|
||||
maunium.net/go/mautrix v0.11.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/tidwall/gjson v1.14.1 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tidwall/sjson v1.2.4 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 // indirect
|
||||
golang.org/x/net v0.0.0-20220513224357-95641704303c // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
maunium.net/go/maulogger/v2 v2.3.2 // indirect
|
||||
)
|
||||
|
|
21
go.sum
21
go.sum
|
@ -1,10 +1,31 @@
|
|||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I=
|
||||
github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
|
||||
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
|
||||
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
||||
golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9 h1:NUzdAbFtCJSXU20AOXgeqaUwg8Ypg4MPYmL+d+rsB5c=
|
||||
golang.org/x/crypto v0.0.0-20220513210258-46612604a0f9/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20220513224357-95641704303c h1:nF9mHSvoKBLkQNQhJZNsc66z2UzAMUbLGjC95CF3pU0=
|
||||
golang.org/x/net v0.0.0-20220513224357-95641704303c/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
maunium.net/go/maulogger/v2 v2.3.2 h1:1XmIYmMd3PoQfp9J+PaHhpt80zpfmMqaShzUTC7FwY0=
|
||||
maunium.net/go/maulogger/v2 v2.3.2/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
|
||||
maunium.net/go/mautrix v0.11.0 h1:B1FBHcvE4Mud+AC+zgNQQOw0JxSVrt40watCejhVA7w=
|
||||
maunium.net/go/mautrix v0.11.0/go.mod h1:K29EcHwsNg6r7fMfwvi0GHQ9o5wSjqB9+Q8RjCIQEjA=
|
||||
|
|
|
@ -6,13 +6,27 @@ import (
|
|||
)
|
||||
|
||||
type Config struct {
|
||||
DB DatabaseConfig
|
||||
Matrix MatrixConfig
|
||||
Server ServerConfig
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Filename string
|
||||
}
|
||||
|
||||
type MatrixConfig struct {
|
||||
AllowedRooms []string
|
||||
DisplayName string
|
||||
LogLevel uint
|
||||
HomeserverURL string
|
||||
UserIdentifier string
|
||||
Password string
|
||||
PickleKey string
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
ListenAddress string
|
||||
}
|
||||
|
||||
func ParseFromFile(path string) (config *Config, err error) {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/config"
|
||||
)
|
||||
|
||||
const DBDriverName = "sqlite3"
|
||||
|
||||
func Open(config *config.DatabaseConfig) (*sql.DB, error) {
|
||||
return sql.Open(DBDriverName, config.Filename)
|
||||
}
|
|
@ -1,29 +1,166 @@
|
|||
package matrix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/config"
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/database"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/crypto"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
func NewClient(config *config.MatrixConfig) (*mautrix.Client, error) {
|
||||
type Client struct {
|
||||
client *mautrix.Client
|
||||
config *config.MatrixConfig
|
||||
db *sql.DB
|
||||
deviceID id.DeviceID
|
||||
olmMachine *crypto.OlmMachine
|
||||
store *sqlStore
|
||||
syncer *mautrix.DefaultSyncer
|
||||
userID id.UserID
|
||||
}
|
||||
|
||||
func NewClient(config *config.MatrixConfig, db *sql.DB) (*Client, error) {
|
||||
client, err := mautrix.NewClient(config.HomeserverURL, "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = client.Login(&mautrix.ReqLogin{
|
||||
Type: mautrix.AuthTypePassword,
|
||||
Identifier: mautrix.UserIdentifier{
|
||||
Type: mautrix.IdentifierTypeUser,
|
||||
User: config.UserIdentifier,
|
||||
},
|
||||
Password: config.Password,
|
||||
StoreCredentials: true,
|
||||
})
|
||||
syncer := mautrix.NewDefaultSyncer()
|
||||
client.Syncer = syncer
|
||||
|
||||
store := &sqlStore{db}
|
||||
client.Store = store
|
||||
|
||||
err = store.CreateTables()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return client, nil
|
||||
userID, err := makeUserID(config.UserIdentifier, config.HomeserverURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deviceID := loadDeviceID(db, userID)
|
||||
|
||||
return &Client{client, config, db, deviceID, nil, store, syncer, userID}, nil
|
||||
}
|
||||
|
||||
func (c *Client) Login() error {
|
||||
c.syncer.OnEventType(event.StateMember, c.handleMemberEvent)
|
||||
|
||||
_, err := c.client.Login(&mautrix.ReqLogin{
|
||||
Type: mautrix.AuthTypePassword,
|
||||
Identifier: mautrix.UserIdentifier{
|
||||
Type: mautrix.IdentifierTypeUser,
|
||||
User: c.config.UserIdentifier,
|
||||
},
|
||||
Password: c.config.Password,
|
||||
DeviceID: c.deviceID,
|
||||
InitialDeviceDisplayName: c.config.DisplayName,
|
||||
StoreCredentials: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Encrypt() error {
|
||||
sqlCryptoStore := crypto.NewSQLCryptoStore(
|
||||
c.db,
|
||||
database.DBDriverName,
|
||||
c.userID.String(),
|
||||
c.deviceID,
|
||||
[]byte(c.config.PickleKey),
|
||||
logger{},
|
||||
)
|
||||
|
||||
err := sqlCryptoStore.CreateTables()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.olmMachine = crypto.NewOlmMachine(c.client, &logger{}, sqlCryptoStore, c.store)
|
||||
|
||||
err = c.olmMachine.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.syncer.OnSync(c.olmMachine.ProcessSyncResponse)
|
||||
|
||||
c.syncer.OnEventType(event.StateEncryption, c.handleEncryptionEvent)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Sync(ctx context.Context, wg *sync.WaitGroup) {
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
err := c.client.SyncWithContext(ctx)
|
||||
if err != nil && err != ctx.Err() {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleMemberEvent(source mautrix.EventSource, evt *event.Event) {
|
||||
if c.olmMachine != nil {
|
||||
c.olmMachine.HandleMemberEvent(evt)
|
||||
}
|
||||
|
||||
c.store.SetMembership(evt.RoomID, evt.GetStateKey(), evt.Content.AsMember().Membership)
|
||||
|
||||
if evt.GetStateKey() == c.userID.String() && evt.Content.AsMember().Membership == event.MembershipInvite {
|
||||
allowed := false
|
||||
for _, room := range c.config.AllowedRooms {
|
||||
if room == evt.RoomID.String() {
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if allowed {
|
||||
_, err := c.client.JoinRoomByID(evt.RoomID)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
} else {
|
||||
_, err := c.client.LeaveRoom(evt.RoomID)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) handleEncryptionEvent(source mautrix.EventSource, evt *event.Event) {
|
||||
c.store.SetEncryptionEvent(evt.RoomID, evt.Content.AsEncryption())
|
||||
}
|
||||
|
||||
func loadDeviceID(db *sql.DB, accountID id.UserID) (deviceID id.DeviceID) {
|
||||
row := db.QueryRow("SELECT device_id FROM crypto_account WHERE account_id = ?;", accountID)
|
||||
|
||||
err := row.Scan(&deviceID)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return deviceID
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package matrix
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
type logger struct{
|
||||
level uint
|
||||
}
|
||||
|
||||
func (l logger) Error(message string, args ...interface{}) {
|
||||
if l.level > 0 {
|
||||
logLevel("error", message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l logger) Warn(message string, args ...interface{}) {
|
||||
if l.level > 1 {
|
||||
logLevel("warning", message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l logger) Debug(message string, args ...interface{}) {
|
||||
if l.level > 2 {
|
||||
logLevel("debug", message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l logger) Trace(message string, args ...interface{}) {
|
||||
if l.level > 3 {
|
||||
logLevel("trace", message, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func logLevel(level, message string, args ...interface{}) {
|
||||
log.Print("[", level, "] ", fmt.Sprintf(message, args...))
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
package matrix
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"maunium.net/go/mautrix"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
type sqlStore struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func (s sqlStore) CreateTables() error {
|
||||
tables := []string{
|
||||
`CREATE TABLE IF NOT EXISTS filter_ids (
|
||||
user_id TEXT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
filter_id TEXT NOT NULL
|
||||
);
|
||||
`,
|
||||
`CREATE TABLE IF NOT EXISTS next_batch_tokens (
|
||||
user_id TEXT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
next_batch_token TEXT NOT NULL
|
||||
);
|
||||
`,
|
||||
`CREATE TABLE IF NOT EXISTS rooms (
|
||||
room_id TEXT PRIMARY KEY ON CONFLICT REPLACE,
|
||||
encryption_event TEXT
|
||||
);
|
||||
`,
|
||||
`CREATE TABLE IF NOT EXISTS room_members (
|
||||
room_id TEXT,
|
||||
user_id TEXT,
|
||||
|
||||
PRIMARY KEY (room_id, user_id)
|
||||
);
|
||||
`,
|
||||
}
|
||||
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, table := range tables {
|
||||
_, err := tx.Exec(table)
|
||||
if err != nil {
|
||||
if err := tx.Rollback(); err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s sqlStore) SaveFilterID(userID id.UserID, filterID string) {
|
||||
_, err := s.db.Exec("INSERT INTO filter_ids VALUES(?, ?);", userID, filterID)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s sqlStore) LoadFilterID(userID id.UserID) (filterID string) {
|
||||
row := s.db.QueryRow("SELECT filter_id FROM filter_ids WHERE user_id = ?;", userID)
|
||||
|
||||
err := row.Scan(&filterID)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return filterID
|
||||
}
|
||||
|
||||
func (s sqlStore) SaveNextBatch(userID id.UserID, nextBatchToken string) {
|
||||
_, err := s.db.Exec("INSERT INTO next_batch_tokens VALUES(?, ?);", userID, nextBatchToken)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s sqlStore) LoadNextBatch(userID id.UserID) (nextBatchToken string) {
|
||||
row := s.db.QueryRow("SELECT next_batch_token FROM next_batch_tokens WHERE user_id = ?;", userID)
|
||||
|
||||
err := row.Scan(&nextBatchToken)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return nextBatchToken
|
||||
}
|
||||
|
||||
func (s sqlStore) SaveRoom(room *mautrix.Room) {
|
||||
}
|
||||
|
||||
func (s sqlStore) LoadRoom(roomID id.RoomID) *mautrix.Room {
|
||||
return mautrix.NewRoom(roomID)
|
||||
}
|
||||
|
||||
func (s sqlStore) IsEncrypted(roomID id.RoomID) (isEncrypted bool) {
|
||||
row := s.db.QueryRow("SELECT encryption_event NOT NULL FROM rooms WHERE room_id = ?;", roomID)
|
||||
|
||||
err := row.Scan(&isEncrypted)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return isEncrypted
|
||||
}
|
||||
|
||||
func (s sqlStore) GetEncryptionEvent(roomID id.RoomID) (encryptionEvent *event.EncryptionEventContent) {
|
||||
row := s.db.QueryRow("SELECT encryption_event FROM rooms WHERE room_id = ?;", roomID)
|
||||
|
||||
var data []byte
|
||||
if err := row.Scan(&data); err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := json.Unmarshal(data, encryptionEvent)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return encryptionEvent
|
||||
}
|
||||
|
||||
func (s sqlStore) FindSharedRooms(userID id.UserID) (sharedRooms []id.RoomID) {
|
||||
rows, err := s.db.Query("SELECT rooms.room_id FROM rooms, (SELECT room_id FROM room_members GROUP BY room_id HAVING COUNT(*) > 1) shared_rooms WHERE shared_rooms.room_id = rooms.room_id AND encryption_event NOT NULL;")
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var roomID string
|
||||
if err := rows.Scan(&roomID); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
sharedRooms = append(sharedRooms, id.RoomID(roomID))
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return sharedRooms
|
||||
}
|
||||
|
||||
func (s sqlStore) SetMembership(roomID id.RoomID, userID string, membership event.Membership) {
|
||||
if membership.IsInviteOrJoin() {
|
||||
_, err := s.db.Exec("INSERT INTO room_members VALUES(?, ?);", roomID, userID)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
} else if membership.IsLeaveOrBan() {
|
||||
_, err := s.db.Exec("DELETE FROM room_members WHERE room_id = ? AND user_id = ?;", roomID, userID)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s sqlStore) SetEncryptionEvent(roomID id.RoomID, encryptionEvent *event.EncryptionEventContent) {
|
||||
var data []byte
|
||||
if encryptionEvent != nil {
|
||||
var err error
|
||||
data, err = json.Marshal(encryptionEvent)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
_, err := s.db.Exec("INSERT INTO rooms VALUES(?, ?);", roomID, data)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package matrix
|
||||
|
||||
import "maunium.net/go/mautrix/id"
|
||||
|
||||
func makeUserID(userIdentifier, homeserverURL string) (id.UserID, error) {
|
||||
userID := id.UserID(userIdentifier)
|
||||
localpart, _, err := userID.Parse()
|
||||
if err != nil {
|
||||
userID = id.NewUserID(userIdentifier, homeserverURL)
|
||||
if _, _, err := userID.ParseAndValidate(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
} else if err := id.ValidateUserLocalpart(localpart); err != nil {
|
||||
return "", err
|
||||
} else if len(userID) > id.UserIDMaxLength {
|
||||
return "", id.ErrUserIDTooLong
|
||||
}
|
||||
|
||||
return userID, nil
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package pretix
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/config"
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/matrix"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
client http.Client
|
||||
matrix *matrix.Client
|
||||
}
|
||||
|
||||
func NewServer(matrix *matrix.Client) *Server {
|
||||
return &Server{
|
||||
matrix: matrix,
|
||||
}
|
||||
}
|
||||
|
||||
func (s Server) ListenAndServe(config *config.ServerConfig, ctx context.Context, wg *sync.WaitGroup) error {
|
||||
http.HandleFunc("/", http.NotFound)
|
||||
http.HandleFunc("/order_placed", s.orderPlaced)
|
||||
|
||||
server := http.Server{
|
||||
Addr: config.ListenAddress,
|
||||
}
|
||||
|
||||
go func() {
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
err := server.Shutdown(context.Background())
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err := server.ListenAndServe()
|
||||
if err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s Server) orderPlaced(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Header.Get("Content-Type") != "application/json" {
|
||||
writeStatus(w, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
|
||||
var data map[string]interface{}
|
||||
err := decoder.Decode(&data)
|
||||
if err != nil {
|
||||
writeStatus(w, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Print(data)
|
||||
}
|
||||
|
||||
func writeStatus(w http.ResponseWriter, code int) {
|
||||
w.WriteHeader(code)
|
||||
io.WriteString(w, http.StatusText(code))
|
||||
}
|
52
main.go
52
main.go
|
@ -1,11 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/config"
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/database"
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/matrix"
|
||||
"git.luj0ga.de/franconian/matrix-pretix/internal/pretix"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -18,9 +24,51 @@ func main() {
|
|||
log.Fatal(err)
|
||||
}
|
||||
|
||||
client, err := matrix.NewClient(&config.Matrix)
|
||||
db, err := database.Open(&config.DB)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
_ = client
|
||||
defer db.Close()
|
||||
|
||||
client, err := matrix.NewClient(&config.Matrix, db)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = client.Login()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = client.Encrypt()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
go func() {
|
||||
wg.Add(1)
|
||||
defer wg.Done()
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
stop()
|
||||
}()
|
||||
|
||||
go client.Sync(ctx, &wg)
|
||||
|
||||
server := pretix.NewServer(client)
|
||||
|
||||
err = server.ListenAndServe(&config.Server, ctx, &wg)
|
||||
if err != nil {
|
||||
stop()
|
||||
wg.Wait()
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
log.Print("done")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue