From 1f64e7427940756e179739c59a2be6b92a9adddc Mon Sep 17 00:00:00 2001
From: Ilya Beltsiukou <968597@gmail.com>
Date: Fri, 2 Apr 2021 20:58:02 +0300
Subject: [PATCH] Implement all event types

---
 client.go               |  18 +++---
 client_examples_test.go |   4 +-
 client_test.go          |   2 +-
 event_types.go          |  33 +++++++++++
 events.go               |   2 +-
 requests_easyjson.go    |   2 +-
 responses_easyjson.go   | 123 ++++++++--------------------------------
 room.go                 |   6 +-
 sync.go                 |   8 +--
 9 files changed, 79 insertions(+), 119 deletions(-)
 create mode 100644 event_types.go

diff --git a/client.go b/client.go
index 0561630..d12f8c4 100644
--- a/client.go
+++ b/client.go
@@ -548,9 +548,9 @@ func (cli *Client) SetStatus(presence, status string) (err error) {
 
 // SendMessageEvent sends a message event into a room. See http://matrix.org/docs/spec/client_server/r0.2.0.html#put-matrix-client-r0-rooms-roomid-send-eventtype-txnid
 // contentJSON should be a pointer to something that can be encoded as JSON using json.Marshal.
-func (cli *Client) SendMessageEvent(roomID string, eventType string, contentJSON interface{}) (resp *RespSendEvent, err error) {
+func (cli *Client) SendMessageEvent(roomID string, eventType EventType, contentJSON interface{}) (resp *RespSendEvent, err error) {
 	txnID := txnID()
-	urlPath := cli.BuildURL("rooms", roomID, "send", eventType, txnID)
+	urlPath := cli.BuildURL("rooms", roomID, "send", eventType.String(), txnID)
 	err = cli.MakeRequest(http.MethodPut, urlPath, contentJSON, &resp)
 	return
 }
@@ -566,21 +566,21 @@ func (cli *Client) SendStateEvent(roomID, eventType, stateKey string, contentJSO
 // SendText sends an m.room.message event into the given room with a msgtype of m.text
 // See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-text
 func (cli *Client) SendText(roomID, text string) (*RespSendEvent, error) {
-	return cli.SendMessageEvent(roomID, "m.room.message",
+	return cli.SendMessageEvent(roomID, MessageEventType,
 		TextMessage{MsgType: TextMessageType, Body: text})
 }
 
 // SendFormattedText sends an m.room.message event into the given room with a msgtype of m.text, supports a subset of HTML for formatting.
 // See https://matrix.org/docs/spec/client_server/r0.6.0#m-text
 func (cli *Client) SendFormattedText(roomID, text, formattedText string) (*RespSendEvent, error) {
-	return cli.SendMessageEvent(roomID, "m.room.message",
+	return cli.SendMessageEvent(roomID, MessageEventType,
 		TextMessage{MsgType: TextMessageType, Body: text, FormattedBody: formattedText, Format: "org.matrix.custom.html"})
 }
 
 // SendImage sends an m.room.message event into the given room with a msgtype of m.image
 // See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-image
 func (cli *Client) SendImage(roomID, body, url string) (*RespSendEvent, error) {
-	return cli.SendMessageEvent(roomID, "m.room.message",
+	return cli.SendMessageEvent(roomID, MessageEventType,
 		ImageMessage{
 			MsgType: ImageMessageType,
 			Body:    body,
@@ -591,7 +591,7 @@ func (cli *Client) SendImage(roomID, body, url string) (*RespSendEvent, error) {
 // SendVideo sends an m.room.message event into the given room with a msgtype of m.video
 // See https://matrix.org/docs/spec/client_server/r0.2.0.html#m-video
 func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
-	return cli.SendMessageEvent(roomID, "m.room.message",
+	return cli.SendMessageEvent(roomID, MessageEventType,
 		VideoMessage{
 			MsgType: VideoMessageType,
 			Body:    body,
@@ -602,7 +602,7 @@ func (cli *Client) SendVideo(roomID, body, url string) (*RespSendEvent, error) {
 // SendNotice sends an m.room.message event into the given room with a msgtype of m.notice
 // See http://matrix.org/docs/spec/client_server/r0.2.0.html#m-notice
 func (cli *Client) SendNotice(roomID, text string) (*RespSendEvent, error) {
-	return cli.SendMessageEvent(roomID, "m.room.message",
+	return cli.SendMessageEvent(roomID, MessageEventType,
 		TextMessage{MsgType: NoticeMessageType, Body: text})
 }
 
@@ -691,8 +691,8 @@ func (cli *Client) UserTyping(roomID string, typing bool, timeout int64) (resp *
 // StateEvent gets a single state event in a room. It will attempt to JSON unmarshal into the given "outContent" struct with
 // the HTTP response body, or return an error.
 // See http://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-r0-rooms-roomid-state-eventtype-statekey
-func (cli *Client) StateEvent(roomID, eventType, stateKey string, outContent interface{}) (err error) {
-	u := cli.BuildURL("rooms", roomID, "state", eventType, stateKey)
+func (cli *Client) StateEvent(roomID string, eventType EventType, stateKey string, outContent interface{}) (err error) {
+	u := cli.BuildURL("rooms", roomID, "state", eventType.String(), stateKey)
 	err = cli.MakeRequest(http.MethodGet, u, nil, outContent)
 	return
 }
diff --git a/client_examples_test.go b/client_examples_test.go
index ccea7c2..5d414be 100644
--- a/client_examples_test.go
+++ b/client_examples_test.go
@@ -10,7 +10,7 @@ func Example_sync() {
 	cli.Store.SaveFilterID("@example:matrix.org", "2")                // Optional: if you know it already
 	cli.Store.SaveNextBatch("@example:matrix.org", "111_222_333_444") // Optional: if you know it already
 	syncer := cli.Syncer.(*DefaultSyncer)
-	syncer.OnEventType("m.room.message", func(ev *Event) {
+	syncer.OnEventType(MessageEventType, func(ev *Event) {
 		fmt.Println("Message: ", ev)
 	})
 
@@ -80,7 +80,7 @@ func ExampleClient_StateEvent() {
 		Name string `json:"name"`
 	}{}
 	cli, _ := NewClient("https://matrix.org", "@example:matrix.org", "abcdef123456")
-	if err := cli.StateEvent("!foo:bar", "m.room.name", "", &content); err != nil {
+	if err := cli.StateEvent("!foo:bar", NameEventType, "", &content); err != nil {
 		panic(err)
 	}
 }
diff --git a/client_test.go b/client_test.go
index a572bc7..d0cd7cd 100644
--- a/client_test.go
+++ b/client_test.go
@@ -76,7 +76,7 @@ func TestClient_StateEvent(t *testing.T) {
 		Name string `json:"name"`
 	}{}
 
-	if err := cli.StateEvent("!foo:bar", "m.room.name", "", &content); err != nil {
+	if err := cli.StateEvent("!foo:bar", NameEventType, "", &content); err != nil {
 		t.Fatalf("StateEvent: error, got %s", err.Error())
 	}
 	if content.Name != "Room Name Goes Here" {
diff --git a/event_types.go b/event_types.go
new file mode 100644
index 0000000..68b7b48
--- /dev/null
+++ b/event_types.go
@@ -0,0 +1,33 @@
+package gomatrix
+
+type EventType string
+
+const (
+	AliasesEventType           EventType = "m.room.aliases"
+	CanonicalAliasEventType    EventType = "m.room.canonical_alias"
+	CreateEventType            EventType = "m.room.create"
+	JoinRulesEventType         EventType = "m.room.join_rules"
+	MemberEventType            EventType = "m.room.member"
+	PowerLevelsEventType       EventType = "m.room.power_levels"
+	RedactionEventType         EventType = "m.room.redaction"
+	MessageEventType           EventType = "m.room.message"
+	MessageFeedbackEventType   EventType = "m.room.message.feedback"
+	NameEventType              EventType = "m.room.name"
+	TopicEventType             EventType = "m.room.topic"
+	AvatarEventType            EventType = "m.room.avatar"
+	TypingEventType            EventType = "m.typing"
+	ReceiptEventType           EventType = "m.receipt"
+	PresenceEventType          EventType = "m.presence"
+	HistoryVisibilityEventType EventType = "m.room.history_visibility"
+	ThirdPartyInviteEventType  EventType = "m.room.third_party_invite"
+	GuestAccessEventType       EventType = "m.room.guest_access"
+	TagEventType               EventType = "m.tag"
+)
+
+func (e EventType) String() string {
+	return string(e)
+}
+
+func (e EventType) KindOf(target EventType) bool {
+	return e == target
+}
diff --git a/events.go b/events.go
index 2aab842..6847748 100644
--- a/events.go
+++ b/events.go
@@ -9,7 +9,7 @@ import (
 type Event struct {
 	StateKey    *string                `json:"state_key,omitempty"`    // The state key for the event. Only present on State Events.
 	Sender      string                 `json:"sender"`                 // The user ID of the sender of the event
-	Type        string                 `json:"type"`                   // The event type
+	Type        EventType              `json:"type"`                   // The event type
 	Timestamp   int64                  `json:"origin_server_ts"`       // The unix timestamp when this message was sent by the origin server
 	ID          string                 `json:"event_id"`               // The unique ID of this event
 	RoomID      string                 `json:"room_id"`                // The room the event was sent to. May be nil (e.g. for presence)
diff --git a/requests_easyjson.go b/requests_easyjson.go
index 23232b6..d9ef247 100644
--- a/requests_easyjson.go
+++ b/requests_easyjson.go
@@ -1045,7 +1045,7 @@ func easyjson11d1a9baDecodeGithubComMatrixOrgGomatrix9(in *jlexer.Lexer, out *Ev
 		case "sender":
 			out.Sender = string(in.String())
 		case "type":
-			out.Type = string(in.String())
+			out.Type = EventType(in.String())
 		case "origin_server_ts":
 			out.Timestamp = int64(in.Int64())
 		case "event_id":
diff --git a/responses_easyjson.go b/responses_easyjson.go
index f9c46b2..90753f8 100644
--- a/responses_easyjson.go
+++ b/responses_easyjson.go
@@ -1281,7 +1281,7 @@ func easyjson559270aeDecodeGithubComMatrixOrgGomatrix8(in *jlexer.Lexer, out *Ev
 		case "sender":
 			out.Sender = string(in.String())
 		case "type":
-			out.Type = string(in.String())
+			out.Type = EventType(in.String())
 		case "origin_server_ts":
 			out.Timestamp = int64(in.Int64())
 		case "event_id":
@@ -3197,80 +3197,7 @@ func (v *RespForgetRoom) UnmarshalJSON(data []byte) error {
 func (v *RespForgetRoom) UnmarshalEasyJSON(l *jlexer.Lexer) {
 	easyjson559270aeDecodeGithubComMatrixOrgGomatrix24(l, v)
 }
-func easyjson559270aeDecodeGithubComMatrixOrgGomatrix25(in *jlexer.Lexer, out *RespError) {
-	isTopLevel := in.IsStart()
-	if in.IsNull() {
-		if isTopLevel {
-			in.Consumed()
-		}
-		in.Skip()
-		return
-	}
-	in.Delim('{')
-	for !in.IsDelim('}') {
-		key := in.UnsafeFieldName(false)
-		in.WantColon()
-		if in.IsNull() {
-			in.Skip()
-			in.WantComma()
-			continue
-		}
-		switch key {
-		case "errcode":
-			out.ErrCode = string(in.String())
-		case "error":
-			out.Err = string(in.String())
-		default:
-			in.SkipRecursive()
-		}
-		in.WantComma()
-	}
-	in.Delim('}')
-	if isTopLevel {
-		in.Consumed()
-	}
-}
-func easyjson559270aeEncodeGithubComMatrixOrgGomatrix25(out *jwriter.Writer, in RespError) {
-	out.RawByte('{')
-	first := true
-	_ = first
-	{
-		const prefix string = ",\"errcode\":"
-		out.RawString(prefix[1:])
-		out.String(string(in.ErrCode))
-	}
-	{
-		const prefix string = ",\"error\":"
-		out.RawString(prefix)
-		out.String(string(in.Err))
-	}
-	out.RawByte('}')
-}
-
-// MarshalJSON supports json.Marshaler interface
-func (v RespError) MarshalJSON() ([]byte, error) {
-	w := jwriter.Writer{}
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix25(&w, v)
-	return w.Buffer.BuildBytes(), w.Error
-}
-
-// MarshalEasyJSON supports easyjson.Marshaler interface
-func (v RespError) MarshalEasyJSON(w *jwriter.Writer) {
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix25(w, v)
-}
-
-// UnmarshalJSON supports json.Unmarshaler interface
-func (v *RespError) UnmarshalJSON(data []byte) error {
-	r := jlexer.Lexer{Data: data}
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix25(&r, v)
-	return r.Error()
-}
-
-// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
-func (v *RespError) UnmarshalEasyJSON(l *jlexer.Lexer) {
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix25(l, v)
-}
-func easyjson559270aeDecodeGithubComMatrixOrgGomatrix26(in *jlexer.Lexer, out *RespCreateRoom) {
+func easyjson559270aeDecodeGithubComMatrixOrgGomatrix25(in *jlexer.Lexer, out *RespCreateRoom) {
 	isTopLevel := in.IsStart()
 	if in.IsNull() {
 		if isTopLevel {
@@ -3301,7 +3228,7 @@ func easyjson559270aeDecodeGithubComMatrixOrgGomatrix26(in *jlexer.Lexer, out *R
 		in.Consumed()
 	}
 }
-func easyjson559270aeEncodeGithubComMatrixOrgGomatrix26(out *jwriter.Writer, in RespCreateRoom) {
+func easyjson559270aeEncodeGithubComMatrixOrgGomatrix25(out *jwriter.Writer, in RespCreateRoom) {
 	out.RawByte('{')
 	first := true
 	_ = first
@@ -3316,27 +3243,27 @@ func easyjson559270aeEncodeGithubComMatrixOrgGomatrix26(out *jwriter.Writer, in
 // MarshalJSON supports json.Marshaler interface
 func (v RespCreateRoom) MarshalJSON() ([]byte, error) {
 	w := jwriter.Writer{}
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix26(&w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix25(&w, v)
 	return w.Buffer.BuildBytes(), w.Error
 }
 
 // MarshalEasyJSON supports easyjson.Marshaler interface
 func (v RespCreateRoom) MarshalEasyJSON(w *jwriter.Writer) {
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix26(w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix25(w, v)
 }
 
 // UnmarshalJSON supports json.Unmarshaler interface
 func (v *RespCreateRoom) UnmarshalJSON(data []byte) error {
 	r := jlexer.Lexer{Data: data}
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix26(&r, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix25(&r, v)
 	return r.Error()
 }
 
 // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
 func (v *RespCreateRoom) UnmarshalEasyJSON(l *jlexer.Lexer) {
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix26(l, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix25(l, v)
 }
-func easyjson559270aeDecodeGithubComMatrixOrgGomatrix27(in *jlexer.Lexer, out *RespCreateFilter) {
+func easyjson559270aeDecodeGithubComMatrixOrgGomatrix26(in *jlexer.Lexer, out *RespCreateFilter) {
 	isTopLevel := in.IsStart()
 	if in.IsNull() {
 		if isTopLevel {
@@ -3367,7 +3294,7 @@ func easyjson559270aeDecodeGithubComMatrixOrgGomatrix27(in *jlexer.Lexer, out *R
 		in.Consumed()
 	}
 }
-func easyjson559270aeEncodeGithubComMatrixOrgGomatrix27(out *jwriter.Writer, in RespCreateFilter) {
+func easyjson559270aeEncodeGithubComMatrixOrgGomatrix26(out *jwriter.Writer, in RespCreateFilter) {
 	out.RawByte('{')
 	first := true
 	_ = first
@@ -3382,27 +3309,27 @@ func easyjson559270aeEncodeGithubComMatrixOrgGomatrix27(out *jwriter.Writer, in
 // MarshalJSON supports json.Marshaler interface
 func (v RespCreateFilter) MarshalJSON() ([]byte, error) {
 	w := jwriter.Writer{}
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix27(&w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix26(&w, v)
 	return w.Buffer.BuildBytes(), w.Error
 }
 
 // MarshalEasyJSON supports easyjson.Marshaler interface
 func (v RespCreateFilter) MarshalEasyJSON(w *jwriter.Writer) {
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix27(w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix26(w, v)
 }
 
 // UnmarshalJSON supports json.Unmarshaler interface
 func (v *RespCreateFilter) UnmarshalJSON(data []byte) error {
 	r := jlexer.Lexer{Data: data}
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix27(&r, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix26(&r, v)
 	return r.Error()
 }
 
 // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
 func (v *RespCreateFilter) UnmarshalEasyJSON(l *jlexer.Lexer) {
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix27(l, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix26(l, v)
 }
-func easyjson559270aeDecodeGithubComMatrixOrgGomatrix28(in *jlexer.Lexer, out *RespBanUser) {
+func easyjson559270aeDecodeGithubComMatrixOrgGomatrix27(in *jlexer.Lexer, out *RespBanUser) {
 	isTopLevel := in.IsStart()
 	if in.IsNull() {
 		if isTopLevel {
@@ -3431,7 +3358,7 @@ func easyjson559270aeDecodeGithubComMatrixOrgGomatrix28(in *jlexer.Lexer, out *R
 		in.Consumed()
 	}
 }
-func easyjson559270aeEncodeGithubComMatrixOrgGomatrix28(out *jwriter.Writer, in RespBanUser) {
+func easyjson559270aeEncodeGithubComMatrixOrgGomatrix27(out *jwriter.Writer, in RespBanUser) {
 	out.RawByte('{')
 	first := true
 	_ = first
@@ -3441,27 +3368,27 @@ func easyjson559270aeEncodeGithubComMatrixOrgGomatrix28(out *jwriter.Writer, in
 // MarshalJSON supports json.Marshaler interface
 func (v RespBanUser) MarshalJSON() ([]byte, error) {
 	w := jwriter.Writer{}
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix28(&w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix27(&w, v)
 	return w.Buffer.BuildBytes(), w.Error
 }
 
 // MarshalEasyJSON supports easyjson.Marshaler interface
 func (v RespBanUser) MarshalEasyJSON(w *jwriter.Writer) {
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix28(w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix27(w, v)
 }
 
 // UnmarshalJSON supports json.Unmarshaler interface
 func (v *RespBanUser) UnmarshalJSON(data []byte) error {
 	r := jlexer.Lexer{Data: data}
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix28(&r, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix27(&r, v)
 	return r.Error()
 }
 
 // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
 func (v *RespBanUser) UnmarshalEasyJSON(l *jlexer.Lexer) {
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix28(l, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix27(l, v)
 }
-func easyjson559270aeDecodeGithubComMatrixOrgGomatrix29(in *jlexer.Lexer, out *DiscoveryInformation) {
+func easyjson559270aeDecodeGithubComMatrixOrgGomatrix28(in *jlexer.Lexer, out *DiscoveryInformation) {
 	isTopLevel := in.IsStart()
 	if in.IsNull() {
 		if isTopLevel {
@@ -3494,7 +3421,7 @@ func easyjson559270aeDecodeGithubComMatrixOrgGomatrix29(in *jlexer.Lexer, out *D
 		in.Consumed()
 	}
 }
-func easyjson559270aeEncodeGithubComMatrixOrgGomatrix29(out *jwriter.Writer, in DiscoveryInformation) {
+func easyjson559270aeEncodeGithubComMatrixOrgGomatrix28(out *jwriter.Writer, in DiscoveryInformation) {
 	out.RawByte('{')
 	first := true
 	_ = first
@@ -3514,25 +3441,25 @@ func easyjson559270aeEncodeGithubComMatrixOrgGomatrix29(out *jwriter.Writer, in
 // MarshalJSON supports json.Marshaler interface
 func (v DiscoveryInformation) MarshalJSON() ([]byte, error) {
 	w := jwriter.Writer{}
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix29(&w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix28(&w, v)
 	return w.Buffer.BuildBytes(), w.Error
 }
 
 // MarshalEasyJSON supports easyjson.Marshaler interface
 func (v DiscoveryInformation) MarshalEasyJSON(w *jwriter.Writer) {
-	easyjson559270aeEncodeGithubComMatrixOrgGomatrix29(w, v)
+	easyjson559270aeEncodeGithubComMatrixOrgGomatrix28(w, v)
 }
 
 // UnmarshalJSON supports json.Unmarshaler interface
 func (v *DiscoveryInformation) UnmarshalJSON(data []byte) error {
 	r := jlexer.Lexer{Data: data}
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix29(&r, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix28(&r, v)
 	return r.Error()
 }
 
 // UnmarshalEasyJSON supports easyjson.Unmarshaler interface
 func (v *DiscoveryInformation) UnmarshalEasyJSON(l *jlexer.Lexer) {
-	easyjson559270aeDecodeGithubComMatrixOrgGomatrix29(l, v)
+	easyjson559270aeDecodeGithubComMatrixOrgGomatrix28(l, v)
 }
 func easyjson559270aeDecode9(in *jlexer.Lexer, out *struct {
 	BaseURL string `json:"base_url"`
diff --git a/room.go b/room.go
index 364deab..d83a653 100644
--- a/room.go
+++ b/room.go
@@ -3,7 +3,7 @@ package gomatrix
 // Room represents a single Matrix room.
 type Room struct {
 	ID    string
-	State map[string]map[string]*Event
+	State map[EventType]map[string]*Event
 }
 
 // PublicRoom represents the information about a public room obtainable from the room directory
@@ -30,7 +30,7 @@ func (room Room) UpdateState(event *Event) {
 }
 
 // GetStateEvent returns the state event for the given type/state_key combo, or nil.
-func (room Room) GetStateEvent(eventType string, stateKey string) *Event {
+func (room Room) GetStateEvent(eventType EventType, stateKey string) *Event {
 	stateEventMap := room.State[eventType]
 	event := stateEventMap[stateKey]
 	return event
@@ -58,6 +58,6 @@ func NewRoom(roomID string) *Room {
 	// Init the State map and return a pointer to the Room
 	return &Room{
 		ID:    roomID,
-		State: make(map[string]map[string]*Event),
+		State: make(map[EventType]map[string]*Event),
 	}
 }
diff --git a/sync.go b/sync.go
index ac326c3..65b53d1 100644
--- a/sync.go
+++ b/sync.go
@@ -25,7 +25,7 @@ type Syncer interface {
 type DefaultSyncer struct {
 	UserID    string
 	Store     Storer
-	listeners map[string][]OnEventListener // event type to listeners array
+	listeners map[EventType][]OnEventListener // event type to listeners array
 }
 
 // OnEventListener can be used with DefaultSyncer.OnEventType to be informed of incoming events.
@@ -36,7 +36,7 @@ func NewDefaultSyncer(userID string, store Storer) *DefaultSyncer {
 	return &DefaultSyncer{
 		UserID:    userID,
 		Store:     store,
-		listeners: make(map[string][]OnEventListener),
+		listeners: make(map[EventType][]OnEventListener),
 	}
 }
 
@@ -92,7 +92,7 @@ func (s *DefaultSyncer) ProcessResponse(res *RespSync, since string) (err error)
 
 // OnEventType allows callers to be notified when there are new events for the given event type.
 // There are no duplicate checks.
-func (s *DefaultSyncer) OnEventType(eventType string, callback OnEventListener) {
+func (s *DefaultSyncer) OnEventType(eventType EventType, callback OnEventListener) {
 	_, exists := s.listeners[eventType]
 	if !exists {
 		s.listeners[eventType] = []OnEventListener{}
@@ -116,7 +116,7 @@ func (s *DefaultSyncer) shouldProcessResponse(resp *RespSync, since string) bool
 	for roomID, roomData := range resp.Rooms.Join {
 		for i := len(roomData.Timeline.Events) - 1; i >= 0; i-- {
 			e := roomData.Timeline.Events[i]
-			if e.Type == "m.room.member" && e.StateKey != nil && *e.StateKey == s.UserID {
+			if e.Type == MemberEventType && e.StateKey != nil && *e.StateKey == s.UserID {
 				m := e.Content["membership"]
 				mship, ok := m.(string)
 				if !ok {