Skip to content

Commit

Permalink
base on the python version
Browse files Browse the repository at this point in the history
  • Loading branch information
rnons committed Dec 5, 2024
1 parent 74a4761 commit 2b1e3e5
Show file tree
Hide file tree
Showing 37 changed files with 34,850 additions and 114,401 deletions.
105 changes: 87 additions & 18 deletions pkg/connector/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ package connector

import (
"context"
"fmt"
"time"

"go.mau.fi/mautrix-googlechat/pkg/gchatmeow"

"go.mau.fi/util/ptr"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/bridgev2/simplevent"
bridgeEvt "maunium.net/go/mautrix/event"

"go.mau.fi/mautrix-googlechat/pkg/gchatmeow"
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/proto"
)

type GChatClient struct {
Expand All @@ -20,15 +25,9 @@ var (
)

func (c *GChatClient) Connect(ctx context.Context) error {
_, err := c.Client.LoadMessagesPage()
if err != nil {
return err
}
err = c.Client.Connect()
if err != nil {
return err
}
return c.onConnect(ctx)
c.Client.OnConnect.AddObserver(func(interface{}) { c.onConnect(ctx) })
c.Client.OnStreamEvent.AddObserver(func(evt interface{}) { c.onStreamEvent(ctx, evt) })
return c.Client.Connect(ctx, time.Duration(90)*time.Minute)
}

func (c *GChatClient) Disconnect() {
Expand Down Expand Up @@ -57,14 +56,17 @@ func (c *GChatClient) IsThisUser(ctx context.Context, userID networkid.UserID) b
func (c *GChatClient) LogoutRemote(ctx context.Context) {
}

func (c *GChatClient) onConnect(ctx context.Context) error {
res, err := c.Client.GetPaginatedWorlds(nil)
func (c *GChatClient) onConnect(ctx context.Context) {
res, err := c.Client.Sync(ctx)
if err != nil {
return err
fmt.Println((err))
return
}
for _, item := range res.WorldItems {
// TODO room name for DM, and full members list
name := item.GetRoomName()
name := item.RoomName
if name == nil {
name = ptr.Ptr("dm")
}
memberMap := map[networkid.UserID]bridgev2.ChatMember{}
memberMap[networkid.UserID(c.UserLogin.ID)] = bridgev2.ChatMember{
EventSender: bridgev2.EventSender{
Expand All @@ -82,12 +84,79 @@ func (c *GChatClient) onConnect(ctx context.Context) error {
CreatePortal: true,
},
ChatInfo: &bridgev2.ChatInfo{
Name: &name,
Name: name,
Members: &bridgev2.ChatMemberList{
MemberMap: memberMap,
},
},
})

}
return nil
}

func (c *GChatClient) onStreamEvent(ctx context.Context, raw any) {
evt, ok := raw.(*proto.Event)
if !ok {
fmt.Println("Invalid event", raw)
return
}
fmt.Println("- onEvent", evt)
switch *evt.Type {
case proto.Event_MESSAGE_POSTED:
msg := evt.Body.GetMessagePosted().Message
senderId := *msg.Creator.UserId.Id
c.UserLogin.Bridge.QueueRemoteEvent(c.UserLogin, &simplevent.Message[*proto.Message]{
EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventMessage,
// LogContext: func(c zerolog.Context) zerolog.Context {
// return c.
// Str("message_id", evtData.MessageID).
// Str("sender", sender.IDStr).
// Str("sender_login", sender.ScreenName).
// Bool("is_from_me", isFromMe)
// },
PortalKey: networkid.PortalKey{
ID: networkid.PortalID(evt.GroupId.String()),
Receiver: c.UserLogin.ID,
},
// CreatePortal: true,
Sender: bridgev2.EventSender{
// IsFromMe: isFromMe,
SenderLogin: networkid.UserLoginID(senderId),
Sender: networkid.UserID(senderId),
},
// Timestamp: evtData.CreatedAt,
},
ID: networkid.MessageID(*msg.LocalId),
// TargetMessage: networkid.MessageID(evtData.MessageID),
// Data: XMDFromEventMessage(&evtData),
Data: msg,
ConvertMessageFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data *proto.Message) (*bridgev2.ConvertedMessage, error) {
return c.convertToMatrix(ctx, portal, intent, data), nil
},
})
}
}

func (c *GChatClient) convertToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, msg *proto.Message) *bridgev2.ConvertedMessage {
parts := make([]*bridgev2.ConvertedMessagePart, 0)

textPart := &bridgev2.ConvertedMessagePart{
ID: "",
Type: bridgeEvt.EventMessage,
Content: &bridgeEvt.MessageEventContent{
MsgType: bridgeEvt.MsgText,
Body: *msg.TextBody,
},
}

if len(textPart.Content.Body) > 0 {
parts = append(parts, textPart)
}

cm := &bridgev2.ConvertedMessage{
Parts: parts,
}

return cm
}
40 changes: 18 additions & 22 deletions pkg/connector/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import (
"context"
"fmt"

"go.mau.fi/mautrix-googlechat/pkg/gchatmeow"
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/cookies"
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/debug"

"maunium.net/go/mautrix/bridge/status"
"maunium.net/go/mautrix/bridgev2"
"maunium.net/go/mautrix/bridgev2/database"
"maunium.net/go/mautrix/bridgev2/networkid"
"maunium.net/go/mautrix/id"

"go.mau.fi/mautrix-googlechat/pkg/gchatmeow"
)

const (
Expand All @@ -35,10 +33,9 @@ func (gc *GChatConnector) GetLoginFlows() []bridgev2.LoginFlow {
func (gc *GChatConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) error {
loginMetadata := login.Metadata.(*UserLoginMetadata)
var client *gchatmeow.Client
clientOptions := gchatmeow.ClientOpts{
Cookies: cookies.NewCookiesFromString(loginMetadata.Cookies),
if loginMetadata.Cookies != nil {
client = gchatmeow.NewClient(loginMetadata.Cookies, "", 0, 0)
}
client = gchatmeow.NewClient(&clientOptions, debug.NewLogger())
c := &GChatClient{
UserLogin: login,
Client: client,
Expand All @@ -52,7 +49,7 @@ type GChatCookieLogin struct {
}

type UserLoginMetadata struct {
Cookies string
Cookies *gchatmeow.Cookies
}

var _ bridgev2.LoginProcessCookies = (*GChatCookieLogin)(nil)
Expand All @@ -72,32 +69,31 @@ func (gl *GChatCookieLogin) Start(ctx context.Context) (*bridgev2.LoginStep, err
func (gl *GChatCookieLogin) Cancel() {}

func (gl *GChatCookieLogin) SubmitCookies(ctx context.Context, strCookies map[string]string) (*bridgev2.LoginStep, error) {
cookies := &cookies.Cookies{}
cookies := &gchatmeow.Cookies{}
cookies.UpdateValues(strCookies)

clientOptions := gchatmeow.ClientOpts{
Cookies: cookies,
client := gchatmeow.NewClient(cookies, "", 0, 0)
err := client.RefreshTokens(ctx)
if err != nil {
return nil, err
}
client := gchatmeow.NewClient(&clientOptions, debug.NewLogger())

initialData, err := client.LoadMessagesPage()
user, err := client.GetSelf(ctx)
if err != nil {
return nil, err
}

user := initialData.CurrentUser.Data

userId := user.Id.Id
userId := user.UserId.Id
ul, err := gl.User.NewLogin(ctx, &database.UserLogin{
ID: networkid.UserLoginID(userId),
RemoteName: user.Fullname,
ID: networkid.UserLoginID(*userId),
RemoteName: user.GetName(),
RemoteProfile: status.RemoteProfile{
Name: user.Fullname,
Email: user.Email,
Name: user.GetName(),
Email: *user.Email,
Avatar: id.ContentURIString(user.GetAvatarUrl()),
},
Metadata: &UserLoginMetadata{
Cookies: cookies.String(),
Cookies: cookies,
},
}, nil)

Expand All @@ -113,7 +109,7 @@ func (gl *GChatCookieLogin) SubmitCookies(ctx context.Context, strCookies map[st
return &bridgev2.LoginStep{
Type: bridgev2.LoginStepTypeComplete,
StepID: LoginStepIDComplete,
Instructions: fmt.Sprintf("Logged in as %s (%s)", user.Fullname, userId),
Instructions: fmt.Sprintf("Logged in as %s (%d)", user.GetName(), userId),
CompleteParams: &bridgev2.LoginCompleteParams{
UserLoginID: ul.ID,
UserLogin: ul,
Expand Down
9 changes: 0 additions & 9 deletions pkg/gchatmeow/TODOS.md

This file was deleted.

125 changes: 125 additions & 0 deletions pkg/gchatmeow/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package gchatmeow

import (
"context"
"fmt"
"net/http"
"net/url"

pb "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"

"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/proto"
)

func (c *Client) gcRequest(ctx context.Context, endpoint string, requestPB protoreflect.ProtoMessage, responsePB protoreflect.ProtoMessage) error {
headers := http.Header{}
if c.xsrfToken != "" {
headers.Set("x-framework-xsrf-token", c.xsrfToken)
}

fmt.Printf("Sending Protocol Buffer request %s:\n%s\n", endpoint, requestPB)
c.apiReqID++

requestData, err := pb.Marshal(requestPB)
if err != nil {
return fmt.Errorf("failed to serialize protocol buffer: %v", err)
}

params := url.Values{}
params.Set("c", string(c.apiReqID))

Check failure on line 30 in pkg/gchatmeow/api.go

View workflow job for this annotation

GitHub Actions / Lint (latest)

conversion from int64 to string yields a string of one rune, not a string of digits
params.Set("rt", "b")
res, err := c.baseRequest(
ctx,
fmt.Sprintf("%s/api/%s", gcBaseURL, endpoint),
"application/x-protobuf",
"proto",
requestData,
headers,
params,
"POST",
)
if err != nil {
return err
}

if err := pb.Unmarshal(res, responsePB); err != nil {
return fmt.Errorf("failed to decode Protocol Buffer response: %v", err)
}

fmt.Printf("Received Protocol Buffer response:\n%s\n", responsePB)
return nil
}

func (c *Client) baseRequest(
ctx context.Context,
urlStr string,
contentType string,
responseType string,
data []byte,
headers http.Header,
params url.Values,
method string,
) ([]byte, error) {
if headers == nil {
headers = http.Header{}
}

if contentType != "" {
headers.Set("content-type", contentType)
}

if responseType == "proto" {
headers.Set("X-Goog-Encode-Response-If-Executable", "base64")
}

if params == nil {
params = url.Values{}
}
params.Set("alt", responseType)
params.Set("key", apiKey)

res, err := c.session.Fetch(ctx, method, urlStr, params, headers, true, data)

if err != nil {
return nil, err
}

return res.Body, nil
}

func (c *Client) getSelfUserStatus(ctx context.Context) (*proto.GetSelfUserStatusResponse, error) {
request := &proto.GetSelfUserStatusRequest{
RequestHeader: c.gcRequestHeader,
}
response := &proto.GetSelfUserStatusResponse{}
err := c.gcRequest(ctx, "get_self_user_status", request, response)
return response, err
}

func (c *Client) getMembers(ctx context.Context, gcid *string) (*proto.GetMembersResponse, error) {
request := &proto.GetMembersRequest{
RequestHeader: c.gcRequestHeader,
MemberIds: []*proto.MemberId{
&proto.MemberId{Id: &proto.MemberId_UserId{
UserId: &proto.UserId{Id: gcid},
}},
},
}
response := &proto.GetMembersResponse{}
err := c.gcRequest(ctx, "get_members", request, response)
return response, err
}

func (c *Client) paginatedWorld(ctx context.Context) (*proto.PaginatedWorldResponse, error) {
request := &proto.PaginatedWorldRequest{
RequestHeader: c.gcRequestHeader,
FetchFromUserSpaces: GetPointer(true),
FetchOptions: []proto.PaginatedWorldRequest_FetchOptions{
proto.PaginatedWorldRequest_EXCLUDE_GROUP_LITE,
},
}
response := &proto.PaginatedWorldResponse{}
err := c.gcRequest(ctx, "paginated_world", request, response)
return response, err
}
Loading

0 comments on commit 2b1e3e5

Please sign in to comment.