Changes
This commit is contained in:
parent
7db9c374cc
commit
9eac960763
26 changed files with 3119 additions and 266 deletions
|
@ -1,8 +0,0 @@
|
|||
package event
|
||||
|
||||
// TODO: Check if it can be deleted
|
||||
|
||||
type EDU struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
}
|
|
@ -1,10 +1,123 @@
|
|||
package event
|
||||
|
||||
type Event struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
RoomId string `json:"roomId,omitempty"`
|
||||
EventType string `json:"eventType,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
ParentId string `json:"parent,omitempty"`
|
||||
Depth int `json:"depth,omitempty"`
|
||||
Id string `json:"event_id,omitempty"`
|
||||
RoomId string `json:"room_id,omitempty"`
|
||||
Sender string `json:"sender,omitempty"`
|
||||
Origin string `json:"origin,omitempty"`
|
||||
Timestamp int64 `json:"origin_server_ts,omitempty"`
|
||||
EventType string `json:"type,omitempty"`
|
||||
StateKey string `json:"state_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
PrevEventHashes map[string]EventHash `json:"prev_events,omitempty"`
|
||||
Depth int `json:"depth,omitempty"`
|
||||
AuthEventHashes map[string]EventHash `json:"auth_events,omitempty"`
|
||||
Unsigned UnsignedData `json:"unsigned,omitempty"`
|
||||
Hashes EventHash `json:"hashes,omitempty"`
|
||||
Signatures map[string]map[string]string `json:"signatures,omitempty"`
|
||||
}
|
||||
|
||||
type StateEvent struct {
|
||||
EventType string `json:"type,omitempty"`
|
||||
StateKey string `json:"state_key,omitempty"`
|
||||
Content string `json:"content,omitempty"`
|
||||
}
|
||||
|
||||
type UnsignedData struct {
|
||||
Age int `json:"age,omitempty"`
|
||||
TransactionId string `json:"transaction_id,omitempty"`
|
||||
ReplaceState string `json:"replaces_state,omitempty"`
|
||||
PrevSender string `json:"prev_sender,omitempty"`
|
||||
PrevContent string `json:"prev_content,omitempty"`
|
||||
RedactedBecause string `json:"redacted_because,omitempty"`
|
||||
}
|
||||
|
||||
type EventHash struct {
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
}
|
||||
|
||||
type CreateEventContent struct {
|
||||
Creator string `json:"creator,omitempty"`
|
||||
Federated bool `json:"m.federate,omitempty"`
|
||||
RoomVersion string `json:"room_version,omitempty"`
|
||||
}
|
||||
|
||||
type JoinRuleEventContent struct {
|
||||
JoinRule string `json:"join_rule,omitempty"`
|
||||
}
|
||||
|
||||
type HistoryVisibilityEventContent struct {
|
||||
HistoryVisibility string `json:"history_visibility,omitempty"`
|
||||
}
|
||||
|
||||
type GuestAccessEventContent struct {
|
||||
GuestAccess string `json:"guest_access,omitempty"`
|
||||
}
|
||||
|
||||
type NameEventContent struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type TopicEventContent struct {
|
||||
Topic string `json:"topic,omitempty"`
|
||||
}
|
||||
|
||||
type MemberEventContent struct {
|
||||
AvatarUrl string `json:"avatar_url,omitempty"`
|
||||
DisplayName string `json:"displayname,omitempty"`
|
||||
Membership string `json:"membership,omitempty"`
|
||||
IsDirect bool `json:"is_direct,omitempty"`
|
||||
}
|
||||
|
||||
type PowerLevelsEventContent struct {
|
||||
Ban int `json:"ban,omitempty"`
|
||||
Events map[string]int `json:"events,omitempty"`
|
||||
EventsDefault int `json:"events_default,omitempty"`
|
||||
Invite int `json:"invite,omitempty"`
|
||||
Kick int `json:"kick,omitempty"`
|
||||
Redact int `json:"redact,omitempty"`
|
||||
StateDefault int `json:"state_default,omitempty"`
|
||||
Users map[string]int `json:"users,omitempty"`
|
||||
UsersDefault int `json:"users_default,omitempty"`
|
||||
Notifications Notifications `json:"notifications,omitempty"`
|
||||
}
|
||||
|
||||
type Notifications struct {
|
||||
Room int `json:"room,omitempty"`
|
||||
}
|
||||
|
||||
type sendMessageRequest struct {
|
||||
MessageType string `json:"msgtype,omitempty"`
|
||||
Body string `json:"body,omitempty"`
|
||||
}
|
||||
|
||||
type createEventResponse struct {
|
||||
EventId string `json:"event_id,omitempty"`
|
||||
}
|
||||
|
||||
type getEventRequest struct{}
|
||||
|
||||
type getEventResponse struct {
|
||||
Content string `json:"content,omitempty"`
|
||||
EventType string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type syncEventsServerRequest struct {
|
||||
Origin string `json:"origin,omitempty"`
|
||||
Timestamp int64 `json:"origin_server_ts,omitempty"`
|
||||
PDUs []*Event `json:"pdus,omitempty"`
|
||||
}
|
||||
|
||||
type syncEventsServerResponse struct {
|
||||
PDUs map[string]pduProcessingResult `json:"pdus,omitempty"`
|
||||
}
|
||||
|
||||
type backfillResponse struct {
|
||||
Origin string `json:"origin,omitempty"`
|
||||
Timestamp int64 `json:"origin_server_ts,omitempty"`
|
||||
PDUs []*Event `json:"pdus,omitempty"`
|
||||
}
|
||||
|
||||
type pduProcessingResult struct {
|
||||
ProcessingError string `json:"error,omitempty"`
|
||||
}
|
||||
|
|
|
@ -1,5 +1,803 @@
|
|||
package event
|
||||
|
||||
func New() (event *Event) {
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/gorilla/mux"
|
||||
"nutfactory.org/Matrix/config"
|
||||
"nutfactory.org/Matrix/entities/device"
|
||||
"nutfactory.org/Matrix/entities/user"
|
||||
"nutfactory.org/Matrix/utils"
|
||||
)
|
||||
|
||||
func New(
|
||||
roomId string,
|
||||
sender string,
|
||||
origin string,
|
||||
timestamp int64,
|
||||
eventType string,
|
||||
stateKey string,
|
||||
content string,
|
||||
txnId string,
|
||||
) (err error, newEvent *Event) {
|
||||
err, eventId := utils.CreateUUID()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
id := generateEventId(eventId)
|
||||
newEvent = &Event{
|
||||
Id: id,
|
||||
RoomId: roomId,
|
||||
Sender: sender,
|
||||
Origin: origin,
|
||||
Timestamp: timestamp,
|
||||
EventType: eventType,
|
||||
StateKey: stateKey,
|
||||
Content: content,
|
||||
Unsigned: UnsignedData{
|
||||
TransactionId: txnId,
|
||||
},
|
||||
}
|
||||
newEvent.AuthEventHashes, err = GetAuthEvents(newEvent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if eventType != "m.room.create" {
|
||||
var depth int
|
||||
newEvent.PrevEventHashes, depth, err = ReadEventsWithoutChild(roomId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
newEvent.Depth = depth + 1
|
||||
}
|
||||
|
||||
newEvent.AuthEventHashes, err = GetAuthEvents(newEvent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newEventBytesForHash, err := json.Marshal(newEvent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err, newEvent.Hashes.SHA256 = utils.Hash(newEventBytesForHash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
newEvent.Unsigned = UnsignedData{}
|
||||
newEventBytesForSign, err := json.Marshal(newEvent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
newEvent.Signatures = utils.SignContent(newEventBytesForSign)
|
||||
newEvent.Unsigned = UnsignedData{
|
||||
TransactionId: txnId,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SendMessageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
request := sendMessageRequest{}
|
||||
errResponse := utils.CheckRequest(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
token, errResponse := utils.GetAccessToken(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
foundUser, err := user.ReadUserFromAccessToken(token)
|
||||
if err != nil || foundUser == nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorCode: "M_UNKNOWN_TOKEN", ErrorMessage: fmt.Sprintf("%s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err = decoder.Decode(&request)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Could not parse JSON: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
roomId := vars["roomId"]
|
||||
eventType := vars["eventType"]
|
||||
txnId := vars["txnId"]
|
||||
if roomId == "" || eventType == "" || txnId == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(r.Body)
|
||||
content := buf.String()
|
||||
err, newEvent := New(
|
||||
roomId,
|
||||
foundUser.Id,
|
||||
config.Homeserver,
|
||||
time.Now().Unix(),
|
||||
eventType,
|
||||
foundUser.Id,
|
||||
content,
|
||||
txnId,
|
||||
)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Error Creating Event: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
err = CreateEvent(newEvent, txnId)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Database Error: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
transaction := &Transaction{
|
||||
Id: txnId,
|
||||
Origin: config.Homeserver,
|
||||
Timestamp: time.Now().Unix(),
|
||||
PDUS: []*Event{newEvent},
|
||||
}
|
||||
servers, err := ReadServers(roomId)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Database Error: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, server := range servers {
|
||||
operation := func() error {
|
||||
return SendTransaction(transaction, server)
|
||||
}
|
||||
notify := func(err error, duration time.Duration) {
|
||||
log.Printf("Error Sending Transaction, retrying in %ss: %s", duration/1000000000, err)
|
||||
}
|
||||
go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify)
|
||||
}
|
||||
response := createEventResponse{
|
||||
EventId: newEvent.Id,
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func CreateStateEventHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
errResponse := utils.CheckRequest(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
token, errResponse := utils.GetAccessToken(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
foundUser, err := user.ReadUserFromAccessToken(token)
|
||||
if err != nil || foundUser == nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorCode: "M_UNKNOWN_TOKEN", ErrorMessage: fmt.Sprintf("%s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
roomId := vars["roomId"]
|
||||
eventType := vars["eventType"]
|
||||
stateKey := vars["stateKey"]
|
||||
if roomId == "" || eventType == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
buf.ReadFrom(r.Body)
|
||||
content := buf.String()
|
||||
err, newEvent := New(
|
||||
roomId,
|
||||
foundUser.Id,
|
||||
config.Homeserver,
|
||||
time.Now().Unix(),
|
||||
eventType,
|
||||
stateKey,
|
||||
content,
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Error Creating Event: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
err = CreateEvent(newEvent, "")
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Database Error: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
err, txnId := utils.CreateUUID()
|
||||
transaction := &Transaction{
|
||||
Id: txnId,
|
||||
Origin: config.Homeserver,
|
||||
Timestamp: time.Now().Unix(),
|
||||
PDUS: []*Event{newEvent},
|
||||
}
|
||||
servers, err := ReadServers(roomId)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Database Error: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, server := range servers {
|
||||
operation := func() error {
|
||||
return SendTransaction(transaction, server)
|
||||
}
|
||||
notify := func(err error, duration time.Duration) {
|
||||
log.Printf("Error Sending Transaction, retrying in %ss: %s", duration/1000000000, err)
|
||||
}
|
||||
go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify)
|
||||
}
|
||||
|
||||
response := createEventResponse{
|
||||
EventId: newEvent.Id,
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetEventUserHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
request := getEventRequest{}
|
||||
errResponse := utils.CheckRequest(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
token, errResponse := utils.GetAccessToken(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
foundUser, err := user.ReadUserFromAccessToken(token)
|
||||
if err != nil || foundUser == nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorCode: "M_UNKNOWN_TOKEN", ErrorMessage: fmt.Sprintf("%s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err = decoder.Decode(&request)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Could not parse JSON: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
roomId := vars["roomId"]
|
||||
eventId := vars["eventId"]
|
||||
if roomId == "" || eventId == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
foundEvent, err := ReadEvent(eventId)
|
||||
if err != nil || foundEvent == nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorCode: "M_NOT_FOUND", ErrorMessage: fmt.Sprintf("Event not found. %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
response := getEventResponse{
|
||||
Content: foundEvent.Content,
|
||||
EventType: foundEvent.EventType,
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetStateEventHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
errResponse := utils.CheckRequest(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
token, errResponse := utils.GetAccessToken(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
foundUser, err := user.ReadUserFromAccessToken(token)
|
||||
if err != nil || foundUser == nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorCode: "M_UNKNOWN_TOKEN", ErrorMessage: fmt.Sprintf("%s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
roomId := vars["roomId"]
|
||||
eventType := vars["eventType"]
|
||||
stateKey := vars["stateKey"]
|
||||
if roomId == "" || eventType == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
foundEvent, err := ReadStateEvent(roomId, eventType, stateKey)
|
||||
if err != nil || foundEvent == nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorCode: "M_NOT_FOUND", ErrorMessage: fmt.Sprintf("Event not found. %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(foundEvent.Content); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func SyncEventsServerHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
request := syncEventsServerRequest{}
|
||||
errResponse := utils.CheckRequest(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
errResponse = utils.CheckAuthHeader(r)
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err := decoder.Decode(&request)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: fmt.Sprintf("Could not parse JSON: %s", err)}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
vars := mux.Vars(r)
|
||||
txnId := vars["txnId"]
|
||||
if txnId == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
response := syncEventsServerResponse{
|
||||
PDUs: make(map[string]pduProcessingResult),
|
||||
}
|
||||
missingEventIds := make(map[string][]string)
|
||||
for _, pdu := range request.PDUs {
|
||||
signatureValid := CheckSignature(*pdu)
|
||||
if !signatureValid {
|
||||
log.Printf("Wrong Signature for Event %s", pdu.Id)
|
||||
response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: "Signature not valid"}
|
||||
continue
|
||||
}
|
||||
authEventsValid, err := CheckAuthEvents(pdu)
|
||||
if !authEventsValid || err != nil {
|
||||
log.Printf("Wrong Auth Events for Event %s", pdu.Id)
|
||||
response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: fmt.Sprintf("Error in Auth Check: %s", err)}
|
||||
//continue
|
||||
}
|
||||
missingParentIds, err := CheckParents(pdu)
|
||||
if len(missingParentIds) > 0 || err != nil {
|
||||
response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: fmt.Sprintf("Error in Parents Check: %s", err)}
|
||||
for _, parentId := range missingParentIds {
|
||||
missingEventIds[pdu.RoomId] = append(missingEventIds[pdu.RoomId], parentId)
|
||||
}
|
||||
}
|
||||
foundEvent, err := ReadEvent(pdu.Id)
|
||||
if foundEvent == nil && err == nil {
|
||||
err = CreateEvent(pdu, txnId)
|
||||
}
|
||||
if err != nil {
|
||||
response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: fmt.Sprintf("Database Error: %s", err)}
|
||||
continue
|
||||
}
|
||||
|
||||
err = HandleEvent(pdu)
|
||||
if err != nil {
|
||||
response.PDUs[pdu.Id] = pduProcessingResult{ProcessingError: fmt.Sprintf("Error in Event-Handling: %s", err)}
|
||||
continue
|
||||
}
|
||||
|
||||
response.PDUs[pdu.Id] = pduProcessingResult{}
|
||||
}
|
||||
|
||||
if len(missingEventIds) > 0 {
|
||||
for roomId, eventIds := range missingEventIds {
|
||||
operation := func() error {
|
||||
return Backfill(eventIds, roomId, request.Origin)
|
||||
}
|
||||
notify := func(err error, duration time.Duration) {
|
||||
log.Printf("Error Backfill, retrying in %s: %s", duration/1000000000, err)
|
||||
}
|
||||
go backoff.RetryNotify(operation, backoff.NewExponentialBackOff(), notify)
|
||||
}
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func BackfillHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
|
||||
errResponse := utils.CheckAuthHeader(r)
|
||||
|
||||
if errResponse != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(errResponse); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
roomId := vars["roomId"]
|
||||
if roomId == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
limit := 50
|
||||
eventIds, ok := r.URL.Query()["v"]
|
||||
log.Printf("%s", eventIds)
|
||||
if !ok || eventIds[0] == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Missing Parameter"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
limitString := r.URL.Query().Get("limit")
|
||||
if limitString != "" {
|
||||
limit, _ = strconv.Atoi(limitString)
|
||||
}
|
||||
pdus := []*Event{}
|
||||
for len(pdus) < limit {
|
||||
newEventIds := []string{}
|
||||
for _, eventId := range eventIds {
|
||||
foundEvent, err := ReadEvent(eventId)
|
||||
if err != nil || foundEvent == nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
if err := json.NewEncoder(w).Encode(utils.ErrorResponse{ErrorMessage: "Event not found"}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for newEventId, _ := range foundEvent.PrevEventHashes {
|
||||
newEventIds = append(newEventIds, newEventId)
|
||||
}
|
||||
pdus = append(pdus, foundEvent)
|
||||
}
|
||||
eventIds = newEventIds
|
||||
}
|
||||
response := backfillResponse{
|
||||
Origin: config.Homeserver,
|
||||
Timestamp: time.Now().Unix(),
|
||||
PDUs: pdus,
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if err := json.NewEncoder(w).Encode(response); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func SendTransaction(transaction *Transaction, homeserver string) (err error) {
|
||||
requestUrl := fmt.Sprintf("https://%s/_matrix/federation/v1/send/%s?", homeserver, transaction.Id)
|
||||
request := syncEventsServerRequest{
|
||||
Origin: transaction.Origin,
|
||||
Timestamp: transaction.Timestamp,
|
||||
PDUs: transaction.PDUS,
|
||||
}
|
||||
reqBody, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest(http.MethodPut, requestUrl, bytes.NewBuffer(reqBody))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
_, err = client.Do(req)
|
||||
return
|
||||
}
|
||||
|
||||
func Backfill(eventIds []string, roomId string, homeserver string) (err error) {
|
||||
requestUrl := fmt.Sprintf("https://%s/_matrix/federation/v1/backfill/%s?", homeserver, roomId)
|
||||
for _, eventId := range eventIds {
|
||||
requestUrl = fmt.Sprintf("%sv=%s&", requestUrl, eventId)
|
||||
}
|
||||
r, err := http.Get(requestUrl)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
response := backfillResponse{}
|
||||
defer r.Body.Close()
|
||||
decoder := json.NewDecoder(r.Body)
|
||||
err = decoder.Decode(&response)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var missingEventIds []string
|
||||
for _, pdu := range response.PDUs {
|
||||
for i, eventId := range missingEventIds {
|
||||
if pdu.Id == eventId {
|
||||
missingEventIds = append(missingEventIds[:i], missingEventIds[i+1:]...)
|
||||
}
|
||||
}
|
||||
signatureValid := CheckSignature(*pdu)
|
||||
if !signatureValid {
|
||||
log.Printf("Wrong Signature for Event %s", pdu.Id)
|
||||
missingEventIds = append(missingEventIds, pdu.Id)
|
||||
continue
|
||||
}
|
||||
authEventsValid, err := CheckAuthEvents(pdu)
|
||||
if !authEventsValid || err != nil {
|
||||
log.Printf("Wrong Auth Events for Event %s", pdu.Id)
|
||||
missingEventIds = append(missingEventIds, pdu.Id)
|
||||
continue
|
||||
}
|
||||
missingParentIds, err := CheckParents(pdu)
|
||||
if len(missingParentIds) > 0 || err != nil {
|
||||
for _, parentId := range missingParentIds {
|
||||
missingEventIds = append(missingEventIds, parentId)
|
||||
}
|
||||
}
|
||||
foundEvent, err := ReadEvent(pdu.Id)
|
||||
if foundEvent == nil && err == nil {
|
||||
err = CreateEvent(pdu, "")
|
||||
}
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
err = HandleEvent(pdu)
|
||||
if err != nil {
|
||||
log.Printf("Error in Event-Handling: %s", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(missingEventIds) > 0 {
|
||||
Backfill(missingEventIds, roomId, homeserver)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func generateEventId(id string) string {
|
||||
return fmt.Sprintf("$%s:%s", id, config.Homeserver)
|
||||
}
|
||||
|
||||
func GetAuthChain(newEvent *Event) (authChain []*Event, err error) {
|
||||
createEvent, err := ReadStateEvent(newEvent.RoomId, "m.room.create", "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if createEvent != nil {
|
||||
authChain = append(authChain, createEvent)
|
||||
}
|
||||
|
||||
powerLevelEvent, err := ReadStateEvent(newEvent.RoomId, "m.room.power_levels", "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if powerLevelEvent != nil {
|
||||
authChain = append(authChain, powerLevelEvent)
|
||||
}
|
||||
|
||||
stateKey := newEvent.Sender
|
||||
if newEvent.EventType == "m.room.member" {
|
||||
stateKey = newEvent.StateKey
|
||||
}
|
||||
|
||||
memberEvent, err := ReadStateEvent(newEvent.RoomId, "m.room.member", stateKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if memberEvent != nil {
|
||||
authChain = append(authChain, memberEvent)
|
||||
}
|
||||
|
||||
joinRuleEvent, err := ReadStateEvent(newEvent.RoomId, "m.room.join_rules", "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if joinRuleEvent != nil && newEvent.EventType == "m.room.member" {
|
||||
authChain = append(authChain, joinRuleEvent)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func GetAuthEvents(newEvent *Event) (authEventHashes map[string]EventHash, err error) {
|
||||
authEventHashes = make(map[string]EventHash)
|
||||
|
||||
authChain, err := GetAuthChain(newEvent)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, authEvent := range authChain {
|
||||
authEventHashes[authEvent.Id] = authEvent.Hashes
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CheckEventHash(id string, hash EventHash) (correct bool, eventFound bool, err error) {
|
||||
foundEvent, err := ReadEvent(id)
|
||||
correct = true
|
||||
eventFound = true
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if foundEvent == nil {
|
||||
eventFound = false
|
||||
return
|
||||
}
|
||||
if hash.SHA256 != foundEvent.Hashes.SHA256 {
|
||||
correct = false
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CheckParents(eventToCheck *Event) (missingParentIds []string, err error) {
|
||||
for key, hash := range eventToCheck.PrevEventHashes {
|
||||
correctHash, foundEvent, err := CheckEventHash(key, hash)
|
||||
if !correctHash || !foundEvent || err != nil {
|
||||
missingParentIds = append(missingParentIds, key)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CheckAuthEvents(eventToCheck *Event) (correct bool, err error) {
|
||||
correct = true
|
||||
authEvents, err := GetAuthEvents(eventToCheck)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for key, hash := range authEvents {
|
||||
if eventToCheck.AuthEventHashes[key].SHA256 != hash.SHA256 {
|
||||
correct = false
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CheckSignature(eventToCheck Event) (correct bool) {
|
||||
correct = false
|
||||
signatures := eventToCheck.Signatures
|
||||
eventToCheck.Unsigned = UnsignedData{}
|
||||
eventToCheck.Signatures = nil
|
||||
jsonString, err := json.Marshal(eventToCheck)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for id, signature := range signatures[eventToCheck.Sender] {
|
||||
key, err := device.ReadKey(id)
|
||||
if err == nil {
|
||||
correct = utils.VerifySignature([]byte(key.Key), jsonString, []byte(signature))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HandleEvents(events []*Event) (err error) {
|
||||
for _, eventToHandle := range events {
|
||||
err = HandleEvent(eventToHandle)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func HandleEvent(eventToHandle *Event) (err error) {
|
||||
if eventToHandle.EventType == "m.room.message" {
|
||||
message := sendMessageRequest{}
|
||||
err = json.Unmarshal([]byte(eventToHandle.Content), &message)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if message.MessageType != "" && message.MessageType == "m.text" {
|
||||
log.Printf("%s: %s", eventToHandle.Sender, message.Body)
|
||||
}
|
||||
} else if eventToHandle.EventType == "m.room.member" {
|
||||
message := MemberEventContent{}
|
||||
err = json.Unmarshal([]byte(eventToHandle.Content), &message)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if message.Membership == "join" {
|
||||
CreateRoomMember(eventToHandle.RoomId, eventToHandle.StateKey)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,15 +2,16 @@ package event
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"nutfactory.org/Matrix/utils/database"
|
||||
)
|
||||
|
||||
func CreateEvent(event *Event, txnId string) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`INSERT INTO event
|
||||
(id, roomId, txnId, eventType, content, parentId, depth)
|
||||
func CreateRoomMember(roomId string, userId string) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`INSERT INTO roomMember
|
||||
(roomId, userId, server)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?)`)
|
||||
(?, ?, ?)`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
|
@ -23,7 +24,7 @@ func CreateEvent(event *Event, txnId string) (err error) {
|
|||
}
|
||||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec(event.Id, event.RoomId, txnId, event.EventType, event.Content, event.ParentId, event.Depth)
|
||||
_, err = stmt.Exec(roomId, userId, strings.Split(userId, ":")[1])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -31,11 +32,129 @@ func CreateEvent(event *Event, txnId string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func CreateParents(eventId string, parentIds map[string]EventHash) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`INSERT INTO parent
|
||||
(eventId, parentId)
|
||||
VALUES
|
||||
(?, ?)`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(sqlStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
for parentId, _ := range parentIds {
|
||||
_, err = stmt.Exec(
|
||||
eventId,
|
||||
parentId,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CreateAuthEvents(eventId string, authEventIds map[string]EventHash) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`INSERT INTO authEvent
|
||||
(eventId, authEventId)
|
||||
VALUES
|
||||
(?, ?)`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(sqlStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
for authEventId, _ := range authEventIds {
|
||||
_, err = stmt.Exec(
|
||||
eventId,
|
||||
authEventId,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CreateEvent(event *Event, txnId string) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`INSERT INTO event
|
||||
(id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(sqlStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
signatures := ""
|
||||
for _, signature := range event.Signatures[event.Origin] {
|
||||
signatures = signature
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(
|
||||
event.Id,
|
||||
event.RoomId,
|
||||
txnId,
|
||||
event.Sender,
|
||||
event.Origin,
|
||||
event.Timestamp,
|
||||
event.EventType,
|
||||
event.StateKey,
|
||||
event.Content,
|
||||
event.Depth,
|
||||
event.Hashes.SHA256,
|
||||
signatures,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tx.Commit()
|
||||
|
||||
err = CreateParents(event.Id, event.PrevEventHashes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = CreateAuthEvents(event.Id, event.AuthEventHashes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CreateEventsFromTransaction(txnId string, pdus map[string]*Event) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`INSERT INTO event
|
||||
(id, roomId, txnId, eventType, content, parentId, depth)
|
||||
(id, roomId, txnId, sender, origin, timestamp, eventType, stateKey, content, depth, hash, signature)
|
||||
VALUES
|
||||
(?, ?, ?, ?, ?, ?, ?)`)
|
||||
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
|
@ -49,7 +168,35 @@ func CreateEventsFromTransaction(txnId string, pdus map[string]*Event) (err erro
|
|||
defer stmt.Close()
|
||||
|
||||
for _, pdu := range pdus {
|
||||
_, err = stmt.Exec(pdu.Id, pdu.RoomId, txnId, pdu.EventType, pdu.Content, pdu.ParentId, pdu.Depth)
|
||||
signatures := ""
|
||||
for _, signature := range pdu.Signatures[pdu.Origin] {
|
||||
signatures = signature
|
||||
}
|
||||
|
||||
_, err = stmt.Exec(
|
||||
pdu.Id,
|
||||
pdu.RoomId,
|
||||
txnId,
|
||||
pdu.Sender,
|
||||
pdu.Origin,
|
||||
pdu.Timestamp,
|
||||
pdu.EventType,
|
||||
pdu.StateKey,
|
||||
pdu.Content,
|
||||
pdu.Depth,
|
||||
pdu.Hashes.SHA256,
|
||||
signatures,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = CreateParents(pdu.Id, pdu.PrevEventHashes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = CreateAuthEvents(pdu.Id, pdu.AuthEventHashes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -59,8 +206,186 @@ func CreateEventsFromTransaction(txnId string, pdus map[string]*Event) (err erro
|
|||
return
|
||||
}
|
||||
|
||||
func ReadEventHash(id string) (hash string, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT hash
|
||||
FROM event
|
||||
WHERE id = '%s'`, id)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
err = rows.Scan(hash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadRoomMembers(roomId string) (roomMembers []string, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT userId
|
||||
FROM roomMember
|
||||
WHERE roomId = '%s'`, roomId)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
roomMembers = []string{}
|
||||
|
||||
for rows.Next() {
|
||||
var foundUser string
|
||||
err = rows.Scan(&foundUser)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
roomMembers = append(roomMembers, foundUser)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadServers(roomId string) (servers []string, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT DISTINCT server
|
||||
FROM roomMember
|
||||
WHERE roomId = '%s'`, roomId)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
servers = []string{}
|
||||
|
||||
for rows.Next() {
|
||||
var foundUser string
|
||||
err = rows.Scan(&foundUser)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
servers = append(servers, foundUser)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadParents(eventId string) (parents map[string]EventHash, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT e.id, e.hash
|
||||
FROM event as e
|
||||
join parent as p on e.id = p.parentId
|
||||
WHERE p.eventId = '%s'`, eventId)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
parents = make(map[string]EventHash)
|
||||
|
||||
for rows.Next() {
|
||||
var eventId string
|
||||
var foundEvent EventHash
|
||||
|
||||
err = rows.Scan(&eventId,
|
||||
&foundEvent.SHA256,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
parents[eventId] = foundEvent
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadEventsWithoutChild(roomId string) (events map[string]EventHash, depth int, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT e.id, e.hash, e.depth
|
||||
FROM event as e
|
||||
LEFT JOIN parent as p on e.id = p.parentId
|
||||
WHERE p.eventId IS NULL AND e.roomId = '%s'`, roomId)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
events = make(map[string]EventHash)
|
||||
|
||||
for rows.Next() {
|
||||
var eventId string
|
||||
var foundEvent EventHash
|
||||
var foundDepth int
|
||||
err = rows.Scan(&eventId,
|
||||
&foundEvent.SHA256,
|
||||
&foundDepth,
|
||||
)
|
||||
|
||||
if foundDepth > depth {
|
||||
depth = foundDepth
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
events[eventId] = foundEvent
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadAuthEvents(eventId string) (authEvents map[string]EventHash, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT e.id, e.hash
|
||||
FROM event as e
|
||||
join authEvent as a on e.id = a.authEventId
|
||||
WHERE a.eventId = '%s'`, eventId)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
authEvents = make(map[string]EventHash)
|
||||
|
||||
for rows.Next() {
|
||||
var eventId string
|
||||
var foundEvent EventHash
|
||||
|
||||
err = rows.Scan(&eventId,
|
||||
&foundEvent.SHA256,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
authEvents[eventId] = foundEvent
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadEvent(id string) (foundEvent *Event, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, eventType, content, parentId, depth
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature
|
||||
FROM event
|
||||
WHERE id = '%s'`, id)
|
||||
|
||||
|
@ -73,13 +398,34 @@ func ReadEvent(id string) (foundEvent *Event, err error) {
|
|||
|
||||
if rows.Next() {
|
||||
foundEvent = &Event{}
|
||||
var signature string
|
||||
err = rows.Scan(&foundEvent.Id,
|
||||
&foundEvent.RoomId,
|
||||
&foundEvent.Unsigned.TransactionId,
|
||||
&foundEvent.Sender,
|
||||
&foundEvent.Origin,
|
||||
&foundEvent.Timestamp,
|
||||
&foundEvent.EventType,
|
||||
&foundEvent.Content,
|
||||
&foundEvent.ParentId,
|
||||
&foundEvent.Depth,
|
||||
&foundEvent.Hashes.SHA256,
|
||||
&signature,
|
||||
)
|
||||
|
||||
foundEvent.Signatures = make(map[string]map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin] = make(map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin]["ed25519:1"] = signature
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.PrevEventHashes, err = ReadParents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.AuthEventHashes, err = ReadAuthEvents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -88,8 +434,120 @@ func ReadEvent(id string) (foundEvent *Event, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func ReadStateEvent(roomId string, eventType string, stateKey string) (foundEvent *Event, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature
|
||||
FROM event
|
||||
WHERE roomId = '%s'
|
||||
AND eventType = '%s'
|
||||
AND stateKey = '%s'`, roomId, eventType, stateKey)
|
||||
|
||||
if stateKey == "" {
|
||||
queryStmt = fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature
|
||||
FROM event
|
||||
WHERE roomId = '%s'
|
||||
AND eventType = '%s'`, roomId, eventType)
|
||||
}
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
foundEvent = &Event{}
|
||||
var signature string
|
||||
err = rows.Scan(&foundEvent.Id,
|
||||
&foundEvent.RoomId,
|
||||
&foundEvent.Unsigned.TransactionId,
|
||||
&foundEvent.Sender,
|
||||
&foundEvent.Origin,
|
||||
&foundEvent.Timestamp,
|
||||
&foundEvent.EventType,
|
||||
&foundEvent.Content,
|
||||
&foundEvent.Depth,
|
||||
&foundEvent.Hashes.SHA256,
|
||||
&signature,
|
||||
)
|
||||
|
||||
foundEvent.Signatures = make(map[string]map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin] = make(map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin]["ed25519:1"] = signature
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.PrevEventHashes, err = ReadParents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.AuthEventHashes, err = ReadAuthEvents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadStateEvents(roomId string, eventType string) (foundEvents []*Event, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature
|
||||
FROM event
|
||||
WHERE roomId = '%s'
|
||||
AND eventType = '%s'`, roomId, eventType)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
foundEvent := &Event{}
|
||||
var signature string
|
||||
err = rows.Scan(&foundEvent.Id,
|
||||
&foundEvent.RoomId,
|
||||
&foundEvent.Unsigned.TransactionId,
|
||||
&foundEvent.Sender,
|
||||
&foundEvent.Origin,
|
||||
&foundEvent.Timestamp,
|
||||
&foundEvent.EventType,
|
||||
&foundEvent.Content,
|
||||
&foundEvent.Depth,
|
||||
&foundEvent.Hashes.SHA256,
|
||||
&signature,
|
||||
)
|
||||
|
||||
foundEvent.Signatures = make(map[string]map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin] = make(map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin]["ed25519:1"] = signature
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.PrevEventHashes, err = ReadParents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.AuthEventHashes, err = ReadAuthEvents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvents = append(foundEvents, foundEvent)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadEventsFromRoom(roomId string) (events map[string]*Event, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, eventType, content, parentId, depth
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature
|
||||
FROM event
|
||||
WHERE roomId = '%s'`, roomId)
|
||||
|
||||
|
@ -104,24 +562,98 @@ func ReadEventsFromRoom(roomId string) (events map[string]*Event, err error) {
|
|||
|
||||
for rows.Next() {
|
||||
foundEvent := &Event{}
|
||||
var signature string
|
||||
err = rows.Scan(&foundEvent.Id,
|
||||
&foundEvent.RoomId,
|
||||
&foundEvent.Unsigned.TransactionId,
|
||||
&foundEvent.Sender,
|
||||
&foundEvent.Origin,
|
||||
&foundEvent.Timestamp,
|
||||
&foundEvent.EventType,
|
||||
&foundEvent.Content,
|
||||
&foundEvent.ParentId,
|
||||
&foundEvent.Depth,
|
||||
&foundEvent.Hashes.SHA256,
|
||||
&signature,
|
||||
)
|
||||
|
||||
foundEvent.Signatures = make(map[string]map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin] = make(map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin]["ed25519:1"] = signature
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.PrevEventHashes, err = ReadParents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.AuthEventHashes, err = ReadAuthEvents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
events[foundEvent.Id] = foundEvent
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadEventsFromTransaction(txnId string) (events map[string]*Event, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, eventType, content, parentId, depth
|
||||
func ReadStateEventsFromRoom(roomId string) (events []*Event, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature
|
||||
FROM event
|
||||
WHERE eventType <> 'm.room.message' AND roomId = '%s'`, roomId)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
foundEvent := &Event{}
|
||||
var signature string
|
||||
err = rows.Scan(&foundEvent.Id,
|
||||
&foundEvent.RoomId,
|
||||
&foundEvent.Unsigned.TransactionId,
|
||||
&foundEvent.Sender,
|
||||
&foundEvent.Origin,
|
||||
&foundEvent.Timestamp,
|
||||
&foundEvent.EventType,
|
||||
&foundEvent.Content,
|
||||
&foundEvent.Depth,
|
||||
&foundEvent.Hashes.SHA256,
|
||||
&signature,
|
||||
)
|
||||
|
||||
foundEvent.Signatures = make(map[string]map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin] = make(map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin]["ed25519:1"] = signature
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.PrevEventHashes, err = ReadParents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.AuthEventHashes, err = ReadAuthEvents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
events = append(events, foundEvent)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ReadEventsFromTransaction(txnId string) (events []*Event, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, roomId, txnId, sender, origin, timestamp, eventType, content, depth, hash, signature
|
||||
FROM event
|
||||
WHERE txnId = '%s'`, txnId)
|
||||
|
||||
|
@ -132,22 +664,41 @@ func ReadEventsFromTransaction(txnId string) (events map[string]*Event, err erro
|
|||
|
||||
defer rows.Close()
|
||||
|
||||
events = make(map[string]*Event)
|
||||
|
||||
for rows.Next() {
|
||||
foundEvent := &Event{}
|
||||
err = rows.Scan(
|
||||
&foundEvent.Id,
|
||||
var signature string
|
||||
err = rows.Scan(&foundEvent.Id,
|
||||
&foundEvent.RoomId,
|
||||
&foundEvent.Unsigned.TransactionId,
|
||||
&foundEvent.Sender,
|
||||
&foundEvent.Origin,
|
||||
&foundEvent.Timestamp,
|
||||
&foundEvent.EventType,
|
||||
&foundEvent.Content,
|
||||
&foundEvent.ParentId,
|
||||
&foundEvent.Depth,
|
||||
&foundEvent.Hashes.SHA256,
|
||||
&signature,
|
||||
)
|
||||
|
||||
foundEvent.Signatures = make(map[string]map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin] = make(map[string]string)
|
||||
foundEvent.Signatures[foundEvent.Origin]["ed25519:1"] = signature
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
events[foundEvent.Id] = foundEvent
|
||||
|
||||
foundEvent.PrevEventHashes, err = ReadParents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
foundEvent.AuthEventHashes, err = ReadAuthEvents(foundEvent.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
events = append(events, foundEvent)
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -155,11 +706,8 @@ func ReadEventsFromTransaction(txnId string) (events map[string]*Event, err erro
|
|||
|
||||
func UpdateEvent(event *Event) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`UPDATE event SET
|
||||
roomId = ?,
|
||||
eventType = ?,
|
||||
content = ?,
|
||||
parentId = ?,
|
||||
depth = ?
|
||||
WHERE id = ?`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
|
@ -174,11 +722,8 @@ func UpdateEvent(event *Event) (err error) {
|
|||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec(
|
||||
event.RoomId,
|
||||
event.EventType,
|
||||
event.Content,
|
||||
event.ParentId,
|
||||
event.Depth,
|
||||
event.Id,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -203,6 +748,52 @@ func DeleteEvent(id string) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
err = DeleteParents(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = DeleteAuthEvents(id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteParents(eventId string) (err error) {
|
||||
queryStmt := fmt.Sprintf(`DELETE FROM parent
|
||||
WHERE eventId = '%s'`, eventId)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = database.DB.Exec(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteAuthEvents(eventId string) (err error) {
|
||||
queryStmt := fmt.Sprintf(`DELETE FROM authEvent
|
||||
WHERE eventId = '%s'`, eventId)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = database.DB.Exec(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
return
|
||||
}
|
||||
|
|
8
entities/event/transaction.go
Normal file
8
entities/event/transaction.go
Normal file
|
@ -0,0 +1,8 @@
|
|||
package event
|
||||
|
||||
type Transaction struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Origin string `json:"origin,omitempty"`
|
||||
Timestamp int64 `json:"timestamp,omitempty"`
|
||||
PDUS []*Event `json:"pdus,omitempty"`
|
||||
}
|
100
entities/event/transactionDatabaseConnector.go
Normal file
100
entities/event/transactionDatabaseConnector.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package event
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"nutfactory.org/Matrix/utils/database"
|
||||
)
|
||||
|
||||
func CreateTransaction(transaction *Transaction) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`INSERT INTO txn
|
||||
(id, origin, timestamp)
|
||||
VALUES
|
||||
(?, ?, ?)`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(sqlStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec(transaction.Id, transaction.Origin, transaction.Timestamp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tx.Commit()
|
||||
return
|
||||
}
|
||||
|
||||
func ReadTransaction(id string) (foundTransaction *Transaction, err error) {
|
||||
queryStmt := fmt.Sprintf(`SELECT id, origin, timestamp
|
||||
FROM txn
|
||||
WHERE id = '%s'`, id)
|
||||
|
||||
rows, err := database.DB.Query(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer rows.Close()
|
||||
|
||||
if rows.Next() {
|
||||
foundTransaction = &Transaction{}
|
||||
err = rows.Scan(&foundTransaction.Id, &foundTransaction.Origin, &foundTransaction.Timestamp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
foundTransaction.PDUS, err = ReadEventsFromTransaction(foundTransaction.Id)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func UpdateTransaction(transaction *Transaction) (err error) {
|
||||
sqlStmt := fmt.Sprintf(`UPDATE txn SET
|
||||
origin = ?,
|
||||
timestamp = ?
|
||||
WHERE id = ?`)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
stmt, err := tx.Prepare(sqlStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
_, err = stmt.Exec(transaction.Origin, transaction.Timestamp, transaction.Id)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
return
|
||||
}
|
||||
|
||||
func DeleteTransaction(id string) (err error) {
|
||||
queryStmt := fmt.Sprintf(`DELETE FROM txn
|
||||
WHERE id = '%s'`, id)
|
||||
|
||||
tx, err := database.DB.Begin()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = database.DB.Exec(queryStmt)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
tx.Commit()
|
||||
return
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue