move gotd fork into repo. (#111)
- update to latest telegram layer - remove some references to fields in tg.Entities that don't exist in the schema - originally added here: https://github.com/beeper/td/commit/820929062a2ba0104397bc01235ab58a9cff780e - referenced here - https://github.com/mautrix/telegramgo/commit/124f0967ed195b5a380c9bd02e170ada9710dde3 - https://github.com/mautrix/telegramgo/commit/4205047aab2e0639217148b5d125bfaab668bd8e
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
package tgtest
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/bin"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/crypto"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/mt"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/proto"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
|
||||
)
|
||||
|
||||
const (
|
||||
// MessageServerResponse is a message type of RPC calls result.
|
||||
MessageServerResponse = proto.MessageServerResponse
|
||||
// MessageFromServer is a message type of server-side updates.
|
||||
MessageFromServer = proto.MessageFromServer
|
||||
)
|
||||
|
||||
// Send sends given message to user session k.
|
||||
// Parameter t denotes MTProto message type. It should be MessageServerResponse or MessageFromServer.
|
||||
func (s *Server) Send(ctx context.Context, k Session, t proto.MessageType, message bin.Encoder) error {
|
||||
conn, ok := s.users.getConnection(k.ID)
|
||||
if !ok {
|
||||
return errors.Errorf("send %T: invalid key: connection %s not found", message, k.AuthKey.String())
|
||||
}
|
||||
|
||||
var b bin.Buffer
|
||||
if err := message.Encode(&b); err != nil {
|
||||
return errors.Wrap(err, "encode")
|
||||
}
|
||||
|
||||
data := crypto.EncryptedMessageData{
|
||||
SessionID: k.ID,
|
||||
MessageDataLen: int32(b.Len()),
|
||||
MessageDataWithPadding: b.Copy(),
|
||||
MessageID: s.msgID.New(t),
|
||||
}
|
||||
|
||||
err := s.cipher.Encrypt(k.AuthKey, data, &b)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "encrypt")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, s.writeTimeout)
|
||||
defer cancel()
|
||||
|
||||
if err := conn.Send(ctx, &b); err != nil {
|
||||
return errors.Wrap(err, "send")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) sendReq(req *Request, t proto.MessageType, encoder bin.Encoder) error {
|
||||
return s.Send(req.RequestCtx, req.Session, t, encoder)
|
||||
}
|
||||
|
||||
// SendResult sends RPC answer using msg as result.
|
||||
func (s *Server) SendResult(req *Request, msg bin.Encoder) error {
|
||||
var buf bin.Buffer
|
||||
|
||||
if err := msg.Encode(&buf); err != nil {
|
||||
return errors.Wrap(err, "encode result")
|
||||
}
|
||||
|
||||
if err := s.sendReq(req, proto.MessageServerResponse, &proto.Result{
|
||||
RequestMessageID: req.MsgID,
|
||||
Result: buf.Raw(),
|
||||
}); err != nil {
|
||||
return errors.Wrapf(err, "send result [%T]", msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendGZIP sends RPC answer and packs it into proto.GZIP.
|
||||
func (s *Server) SendGZIP(req *Request, msg bin.Encoder) error {
|
||||
var buf bin.Buffer
|
||||
|
||||
if err := msg.Encode(&buf); err != nil {
|
||||
return errors.Wrap(err, "encode gzip data")
|
||||
}
|
||||
|
||||
return s.SendResult(req, proto.GZIP{Data: buf.Buf})
|
||||
}
|
||||
|
||||
// SendErr sends RPC answer using given error as result.
|
||||
func (s *Server) SendErr(req *Request, e *tgerr.Error) error {
|
||||
return s.SendResult(req, &mt.RPCError{
|
||||
ErrorCode: e.Code,
|
||||
ErrorMessage: e.Message,
|
||||
})
|
||||
}
|
||||
|
||||
// SendBool sends RPC answer using given bool as result.
|
||||
// Usually used in methods without explicit response.
|
||||
func (s *Server) SendBool(req *Request, r bool) error {
|
||||
var msg tg.BoolClass = &tg.BoolTrue{}
|
||||
if !r {
|
||||
msg = &tg.BoolFalse{}
|
||||
}
|
||||
return s.SendResult(req, msg)
|
||||
}
|
||||
|
||||
// SendVector sends RPC answer using given vector as result.
|
||||
func (s *Server) SendVector(req *Request, msgs ...bin.Encoder) error {
|
||||
return s.SendResult(req, &genericVector{Elems: msgs})
|
||||
}
|
||||
|
||||
// sendSessionCreated sends mt.NewSessionCreated `new_session_created` notification.
|
||||
func (s *Server) sendSessionCreated(ctx context.Context, k Session, serverSalt int64) error {
|
||||
if err := s.Send(ctx, k, proto.MessageFromServer, &mt.NewSessionCreated{
|
||||
FirstMsgID: s.msgID.New(proto.MessageFromClient),
|
||||
ServerSalt: serverSalt,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "send sessionCreated")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendPong sends response for mt.PingRequest request.
|
||||
func (s *Server) SendPong(req *Request, pingID int64) error {
|
||||
if err := s.sendReq(req, proto.MessageServerResponse, &mt.Pong{
|
||||
MsgID: req.MsgID,
|
||||
PingID: pingID,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "send pong")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendEternalSalt sends response for mt.GetFutureSaltsRequest.
|
||||
// It sends an `eternal` salt, which valid until maximum possible date.
|
||||
func (s *Server) SendEternalSalt(req *Request) error {
|
||||
return s.SendFutureSalts(req, mt.FutureSalt{
|
||||
ValidSince: 1,
|
||||
ValidUntil: math.MaxInt32,
|
||||
Salt: 10,
|
||||
})
|
||||
}
|
||||
|
||||
// SendFutureSalts sends response for mt.GetFutureSaltsRequest.
|
||||
func (s *Server) SendFutureSalts(req *Request, salts ...mt.FutureSalt) error {
|
||||
if err := s.Send(req.RequestCtx, req.Session, proto.MessageServerResponse, &mt.FutureSalts{
|
||||
ReqMsgID: req.MsgID,
|
||||
Now: int(s.clock.Now().Unix()),
|
||||
Salts: salts,
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "send future salts")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendUpdates sends given updates to user session k.
|
||||
func (s *Server) SendUpdates(ctx context.Context, k Session, updates ...tg.UpdateClass) error {
|
||||
if len(updates) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := s.Send(ctx, k, proto.MessageFromServer, &tg.Updates{
|
||||
Updates: updates,
|
||||
Date: int(s.clock.Now().Unix()),
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "send updates")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendAck sends acknowledgment for received message.
|
||||
func (s *Server) SendAck(ctx context.Context, k Session, ids ...int64) error {
|
||||
if err := s.Send(ctx, k, proto.MessageFromServer, &mt.MsgsAck{MsgIDs: ids}); err != nil {
|
||||
return errors.Wrap(err, "send ack")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ForceDisconnect forcibly disconnect user from server.
|
||||
// It deletes MTProto session (session_id), but not auth key.
|
||||
func (s *Server) ForceDisconnect(k Session) {
|
||||
s.users.deleteConnection(k.ID)
|
||||
}
|
||||
Reference in New Issue
Block a user