github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/protocol/gregor1/factory.go (about)

     1  package gregor1
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"sort"
     7  	"time"
     8  
     9  	"github.com/keybase/client/go/gregor"
    10  	"github.com/keybase/go-codec/codec"
    11  )
    12  
    13  type ObjFactory struct{}
    14  
    15  func (o ObjFactory) MakeUID(b []byte) (gregor.UID, error)           { return UID(b), nil }
    16  func (o ObjFactory) MakeMsgID(b []byte) (gregor.MsgID, error)       { return MsgID(b), nil }
    17  func (o ObjFactory) MakeDeviceID(b []byte) (gregor.DeviceID, error) { return DeviceID(b), nil }
    18  func (o ObjFactory) MakeBody(b []byte) (gregor.Body, error)         { return Body(b), nil }
    19  func (o ObjFactory) MakeSystem(s string) (gregor.System, error)     { return System(s), nil }
    20  func (o ObjFactory) MakeCategory(s string) (gregor.Category, error) { return Category(s), nil }
    21  
    22  func castUID(uid gregor.UID) (ret UID, err error) {
    23  	if uid == nil {
    24  		return
    25  	}
    26  	ret, ok := uid.(UID)
    27  	if !ok {
    28  		err = errors.New("bad UID; wrong type")
    29  	}
    30  	return
    31  }
    32  
    33  func castDeviceID(d gregor.DeviceID) (ret DeviceID, err error) {
    34  	if d == nil {
    35  		return
    36  	}
    37  	ret, ok := d.(DeviceID)
    38  	if !ok {
    39  		err = errors.New("bad Device ID; wrong type")
    40  	}
    41  	return
    42  }
    43  
    44  func castItem(i gregor.Item) (ret ItemAndMetadata, err error) {
    45  	ret, ok := i.(ItemAndMetadata)
    46  	if !ok {
    47  		err = errors.New("bad Item; wrong type")
    48  	}
    49  	return
    50  }
    51  
    52  func castInBandMessage(i gregor.InBandMessage) (ret InBandMessage, err error) {
    53  	ret, ok := i.(InBandMessage)
    54  	if !ok {
    55  		err = errors.New("bad InBandMessage; wrong type")
    56  	}
    57  	return
    58  }
    59  
    60  func timeToTimeOrOffset(timeIn *time.Time) (too TimeOrOffset) {
    61  	if timeIn != nil {
    62  		too.Time_ = ToTime(*timeIn)
    63  	}
    64  	return
    65  }
    66  
    67  func (o ObjFactory) makeMetadata(uid gregor.UID, msgid gregor.MsgID, devid gregor.DeviceID, ctime time.Time, i gregor.InBandMsgType) (Metadata, error) {
    68  	uid2, e := castUID(uid)
    69  	if e != nil {
    70  		return Metadata{}, e
    71  	}
    72  	devid2, e := castDeviceID(devid)
    73  	if e != nil {
    74  		return Metadata{}, e
    75  	}
    76  
    77  	return Metadata{
    78  		Uid_:           uid2,
    79  		MsgID_:         MsgID(msgid.Bytes()),
    80  		Ctime_:         ToTime(ctime),
    81  		DeviceID_:      devid2,
    82  		InBandMsgType_: int(i),
    83  	}, nil
    84  }
    85  
    86  func (o ObjFactory) makeItem(c gregor.Category, d *time.Time, b gregor.Body) *Item {
    87  	return &Item{
    88  		Dtime_:    timeToTimeOrOffset(d),
    89  		Category_: Category(c.String()),
    90  		Body_:     Body(b.Bytes()),
    91  	}
    92  }
    93  
    94  func (o ObjFactory) MakeItem(u gregor.UID, msgid gregor.MsgID, deviceid gregor.DeviceID, ctime time.Time, c gregor.Category, dtime *time.Time, body gregor.Body) (gregor.Item, error) {
    95  	md, err := o.makeMetadata(u, msgid, deviceid, ctime, gregor.InBandMsgTypeUpdate)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	return ItemAndMetadata{
   100  		Md_:   &md,
   101  		Item_: o.makeItem(c, dtime, body),
   102  	}, nil
   103  }
   104  
   105  func (o ObjFactory) MakeReminder(i gregor.Item, seqno int, t time.Time) (gregor.Reminder, error) {
   106  	it, ok := i.(ItemAndMetadata)
   107  	if !ok {
   108  		return nil, errors.New("item is not gregor1.ItemAndMetadata")
   109  	}
   110  	return Reminder{
   111  		Item_:       it,
   112  		Seqno_:      seqno,
   113  		RemindTime_: ToTime(t),
   114  	}, nil
   115  }
   116  
   117  func (o ObjFactory) MakeDismissalByRange(uid gregor.UID, msgid gregor.MsgID, devid gregor.DeviceID, ctime time.Time, c gregor.Category, d time.Time, skipMsgIDs []gregor.MsgID) (gregor.InBandMessage, error) {
   118  	md, err := o.makeMetadata(uid, msgid, devid, ctime, gregor.InBandMsgTypeUpdate)
   119  	if err != nil {
   120  		return nil, err
   121  	}
   122  	var skips []MsgID
   123  	for _, s := range skipMsgIDs {
   124  		skips = append(skips, MsgID(s.Bytes()))
   125  	}
   126  	return InBandMessage{
   127  		StateUpdate_: &StateUpdateMessage{
   128  			Md_: md,
   129  			Dismissal_: &Dismissal{
   130  				Ranges_: []MsgRange{{
   131  					EndTime_:    timeToTimeOrOffset(&d),
   132  					Category_:   Category(c.String()),
   133  					SkipMsgIDs_: skips,
   134  				}},
   135  			},
   136  		},
   137  	}, nil
   138  }
   139  
   140  func (o ObjFactory) MakeDismissalByIDs(uid gregor.UID, msgid gregor.MsgID, devid gregor.DeviceID, ctime time.Time, ids []gregor.MsgID) (gregor.InBandMessage, error) {
   141  	md, err := o.makeMetadata(uid, msgid, devid, ctime, gregor.InBandMsgTypeUpdate)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	ourIds := make([]MsgID, len(ids))
   146  	for i, id := range ids {
   147  		ourIds[i] = MsgID(id.Bytes())
   148  	}
   149  	return InBandMessage{
   150  		StateUpdate_: &StateUpdateMessage{
   151  			Md_: md,
   152  			Dismissal_: &Dismissal{
   153  				MsgIDs_: ourIds,
   154  			},
   155  		},
   156  	}, nil
   157  }
   158  
   159  func (o ObjFactory) MakeStateSyncMessage(uid gregor.UID, msgid gregor.MsgID, devid gregor.DeviceID, ctime time.Time) (gregor.InBandMessage, error) {
   160  	md, err := o.makeMetadata(uid, msgid, devid, ctime, gregor.InBandMsgTypeUpdate)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  	return InBandMessage{
   165  		StateSync_: &StateSyncMessage{
   166  			Md_: md,
   167  		},
   168  	}, nil
   169  }
   170  
   171  type itemSlice []ItemAndMetadata
   172  
   173  func (its itemSlice) Len() int      { return len(its) }
   174  func (its itemSlice) Swap(i, j int) { its[i], its[j] = its[j], its[i] }
   175  
   176  // Less returns true if i's ctime is before j's, or if they're equal and
   177  // i's MsgID is lexicographically before j's.
   178  func (its itemSlice) Less(i, j int) bool {
   179  	mI, mJ := its[i].Metadata(), its[j].Metadata()
   180  	if mI != nil && mJ != nil {
   181  		if mI.CTime().Equal(mJ.CTime()) {
   182  			if mI.MsgID() != nil && mJ.MsgID() != nil {
   183  				return bytes.Compare(mI.MsgID().Bytes(), mJ.MsgID().Bytes()) < 0
   184  			} else {
   185  				return mI.MsgID() == nil
   186  			}
   187  		}
   188  		return mI.CTime().Before(mJ.CTime())
   189  	}
   190  	return mI == nil
   191  }
   192  
   193  func (o ObjFactory) MakeState(items []gregor.Item) (gregor.State, error) {
   194  	ourItems := make(itemSlice, 0, len(items))
   195  	for _, item := range items {
   196  		ourItem, err := castItem(item)
   197  		if err != nil {
   198  			return nil, err
   199  		}
   200  		ourItems = append(ourItems, ourItem)
   201  	}
   202  	sort.Sort(ourItems)
   203  	return State{Items_: ourItems}, nil
   204  }
   205  
   206  func (o ObjFactory) MakeStateWithLookupTable(items []gregor.Item, table map[string]gregor.Item) (gregor.State, error) {
   207  	return o.MakeState(items)
   208  }
   209  
   210  func (o ObjFactory) MakeMetadata(uid gregor.UID, msgid gregor.MsgID, devid gregor.DeviceID, ctime time.Time, i gregor.InBandMsgType) (gregor.Metadata, error) {
   211  	return o.makeMetadata(uid, msgid, devid, ctime, gregor.InBandMsgTypeUpdate)
   212  }
   213  
   214  func (o ObjFactory) MakeInBandMessageFromItem(i gregor.Item) (gregor.InBandMessage, error) {
   215  	ourItem, err := castItem(i)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	return InBandMessage{
   220  		StateUpdate_: &StateUpdateMessage{
   221  			Md_:       *ourItem.Md_,
   222  			Creation_: ourItem.Item_,
   223  		},
   224  	}, nil
   225  }
   226  
   227  func (o ObjFactory) MakeMessageFromInBandMessage(i gregor.InBandMessage) (gregor.Message, error) {
   228  	ourInBandMessage, err := castInBandMessage(i)
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  	return Message{
   233  		Ibm_: &ourInBandMessage,
   234  	}, nil
   235  }
   236  
   237  func (o ObjFactory) UnmarshalState(b []byte) (gregor.State, error) {
   238  	var state State
   239  	err := codec.NewDecoderBytes(b, &codec.MsgpackHandle{WriteExt: true}).
   240  		Decode(&state)
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  
   245  	return state, nil
   246  }
   247  
   248  func (o ObjFactory) UnmarshalMessage(b []byte) (gregor.Message, error) {
   249  	var message Message
   250  	err := codec.NewDecoderBytes(b, &codec.MsgpackHandle{WriteExt: true}).Decode(&message)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  	return message, nil
   255  }
   256  
   257  func (o ObjFactory) MakeTimeOrOffsetFromTime(t time.Time) (gregor.TimeOrOffset, error) {
   258  	return timeToTimeOrOffset(&t), nil
   259  }
   260  
   261  func (o ObjFactory) MakeTimeOrOffsetFromOffset(d time.Duration) (gregor.TimeOrOffset, error) {
   262  	return TimeOrOffset{Offset_: DurationMsec(d / time.Millisecond)}, nil
   263  }
   264  
   265  func (o ObjFactory) ExportTimeOrOffset(t gregor.TimeOrOffset) TimeOrOffset {
   266  	if t.Time() != nil {
   267  		return TimeOrOffset{
   268  			Time_: ToTime(*t.Time()),
   269  		}
   270  	}
   271  	if t.Offset() != nil {
   272  		return TimeOrOffset{
   273  			Offset_: DurationMsec(*t.Offset() / time.Millisecond),
   274  		}
   275  	}
   276  	return TimeOrOffset{}
   277  }
   278  
   279  func (o ObjFactory) ExportTimeOrOffsets(ts []gregor.TimeOrOffset) (res []TimeOrOffset) {
   280  	for _, t := range ts {
   281  		res = append(res, o.ExportTimeOrOffset(t))
   282  	}
   283  	return res
   284  }
   285  
   286  func (o ObjFactory) MakeReminderID(u gregor.UID, msgid gregor.MsgID, seqno int) (gregor.ReminderID, error) {
   287  	return ReminderID{Uid_: u.Bytes(), MsgID_: msgid.Bytes(), Seqno_: seqno}, nil
   288  }
   289  
   290  func (o ObjFactory) MakeReminderSetFromReminders(reminders []gregor.Reminder, moreRemindersReady bool) (gregor.ReminderSet, error) {
   291  	ret := ReminderSet{MoreRemindersReady_: moreRemindersReady}
   292  	for _, reminder := range reminders {
   293  		if r, ok := reminder.(Reminder); ok {
   294  			ret.Reminders_ = append(ret.Reminders_, r)
   295  		} else {
   296  			return nil, errors.New("Can't upcast reminder")
   297  		}
   298  	}
   299  	return ret, nil
   300  }
   301  
   302  func (o ObjFactory) MakeOutOfBandMessage(uid gregor.UID, system gregor.System, body gregor.Body) gregor.Message {
   303  	return Message{
   304  		Oobm_: &OutOfBandMessage{Uid_: uid.Bytes(), System_: System(system.String()), Body_: body.Bytes()},
   305  	}
   306  }
   307  
   308  var _ gregor.ObjFactory = ObjFactory{}