diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 251a70f5..e4ea0f0c 100755 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -29,14 +29,14 @@ func (*PingParams) CRC() uint32 { return 0x7abe77ec } -func GenerateMessageId(prevID int64) int64 { +func GenerateMessageId(prevID int64, offset int64) int64 { const billion = 1000 * 1000 * 1000 - unixnano := time.Now().UnixNano() + unixnano := time.Now().UnixNano() + (offset * billion) seconds := unixnano / billion nanoseconds := unixnano % billion newID := (seconds << 32) | (nanoseconds & -4) if newID <= prevID { - return GenerateMessageId(prevID) + return GenerateMessageId(prevID, offset) } return newID } diff --git a/mtproto.go b/mtproto.go index db5c15cb..5938bc86 100755 --- a/mtproto.go +++ b/mtproto.go @@ -5,8 +5,10 @@ package gogram import ( "context" "crypto/rsa" + "encoding/json" "fmt" "io" + "net/http" "net/url" "os" "path/filepath" @@ -37,6 +39,7 @@ type MTProto struct { routineswg sync.WaitGroup memorySession bool tcpActive bool + timeOffset int64 authKey []byte @@ -124,6 +127,8 @@ func NewMTProto(c Config) (*MTProto, error) { if err := mtproto.loadAuth(c.StringSession, loaded); err != nil { return nil, errors.Wrap(err, "loading auth") } + + //mtproto.offsetTime() return mtproto, nil } @@ -538,6 +543,9 @@ messageTypeSwitching: case *objects.BadMsgNotification: badMsg := BadMsgErrorFromNative(message) + if badMsg.Code == 16 || badMsg.Code == 17 { + m.offsetTime() + } m.Logger.Debug("BadMsgNotification: " + badMsg.Error()) return badMsg case *objects.RpcResult: @@ -589,6 +597,33 @@ func MessageRequireToAck(msg tl.Object) bool { } } +func (m *MTProto) offsetTime() { + currentLocalTime := time.Now().Unix() + tempClient := http.Client{ + Timeout: 5 * time.Second, + } + + resp, err := tempClient.Get("http://worldtimeapi.org/api/ip") + if err != nil { + m.Logger.Error(errors.Wrap(err, "offsetting time")) + return + } + + defer resp.Body.Close() + + var timeResponse struct { + Unixtime int64 `json:"unixtime"` + } + + if err := json.NewDecoder(resp.Body).Decode(&timeResponse); err != nil { + m.Logger.Error(errors.Wrap(err, "offsetting time")) + return + } + + m.timeOffset = timeResponse.Unixtime - currentLocalTime + m.Logger.Info("SystemTime is out of sync, offsetting time by " + strconv.FormatInt(m.timeOffset, 10) + " seconds") +} + func closeOnCancel(ctx context.Context, c io.Closer) { <-ctx.Done() go func() {