chromium/components/feed/core/proto/v2/store.proto

// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

syntax = "proto3";

package feedstore;

import "components/feed/core/proto/v2/wire/content_id.proto";
import "components/feed/core/proto/v2/wire/feed_action.proto";
import "components/feed/core/proto/v2/wire/stream_structure.proto";
import "components/feed/core/proto/v2/wire/web_feed_matcher.proto";
import "components/feed/core/proto/v2/wire/web_feeds.proto";

option optimize_for = LITE_RUNTIME;

// Actual data stored by the client.
// This data is sourced from the wire protocol, which is converted upon receipt.
//
// This is the 'value' in the key/value store.
// Keys are defined as:
// [Key format]                     -> [Record field]
// S/<stream-key>                   -> stream_data
// T/<stream-key>/<sequence-number> -> stream_structures
// c/<stream-key>/<content-id>      -> content
// s/<stream-key>/<content-id>      -> shared_state
// a/<action-id>                    -> action
// m                                -> metadata
// subs                             -> subscribed_web_feeds
// recommendedIndex                 -> recommended_web_feed_index
// R/<web_feed_id>                  -> recommended_web_feed
// W/<operation-id>                 -> pending_web_feed_operation
// v/<docid>/<timestamp>            -> docview
message Record {
  oneof data {
    StreamData stream_data = 1;
    StreamStructureSet stream_structures = 2;
    Content content = 3;
    StoredAction local_action = 4;
    StreamSharedState shared_state = 5;
    Metadata metadata = 6;
    SubscribedWebFeeds subscribed_web_feeds = 7;
    WebFeedInfo recommended_web_feed = 8;
    RecommendedWebFeedIndex recommended_web_feed_index = 9;
    PendingWebFeedOperation pending_web_feed_operation = 10;
    DocView doc_view = 11;
  }
}

// List of the hashes for all the contents in a collection (carousel, list,
// or 2-column) if multiple items show up in a row. Otherwise, it just contain
// a single hash value.
message StreamContentHashList {
  // The hash of the content URL.
  repeated uint32 hashes = 1;
}

// Data about the Feed stream. There is at most one instance of StreamData.
message StreamData {
  // Root ContentId, as provided by the server.
  feedwire.ContentId content_id = 1;
  // Token used to request a 'more' request to the server.
  bytes next_page_token = 2;
  // The unix timestamp in milliseconds that the most recent content was added.
  int64 last_added_time_millis = 4;
  // The content IDs of the shared state for this stream.
  repeated feedwire.ContentId shared_state_ids = 6;
  // Was this feed signed in.
  bool signed_in = 7;
  // If signed_in, this is the account gaia tied to this stream data.
  string gaia = 13;
  // If signed_in, this is the account email tied to this stream data.
  string email = 14;
  // Is activity logging enabled?
  bool logging_enabled = 8;
  // Has the privacy notice been fulfilled?
  bool privacy_notice_fulfilled = 9;
  // Stream ID. Should match the id value stored in the record's key.
  string stream_key = 10;
  // List of hashes for all the contents contained in the stream.
  repeated StreamContentHashList content_hashes = 11;
  // Root EventID provided by the server.
  bytes root_event_id = 12;

  reserved 3, 5, 15;
}

// Data that doesn't belong to a stream.
message Metadata {
  // Session identifier used for signed-out feed requests and interactions.
  message SessionID {
    string token = 1;
    int64 expiry_time_ms = 2;
  }

  // Metadata about a specific stream.
  message StreamMetadata {
    string stream_key = 1;
    // Whether the stream data is known to be stale. This can happen in the
    // WebFeed stream if the subscription list changes.
    bool is_known_stale = 3;
    // If this stream has been viewed before, this is the list of content in the
    // stream (`StreamData.content_hashes`). This is used to determine whether
    // the user has already seen a stored stream's data.
    repeated StreamContentHashList view_content_hashes = 4;

    message ContentLifetime {
      int64 stale_age_ms = 1;
      int64 invalid_age_ms = 2;
    }
    ContentLifetime content_lifetime = 5;
    // The unix timestamp in milliseconds that the stream was fetched last time.
    int64 last_fetch_time_millis = 6;

    // The unix timestamp in milliseconds that the feed response is produced on
    // the server. This is returned from the server and based on server clock.
    int64 last_server_response_time_millis = 7;

    // List of IDs of contents that have been viewed by the user. A content is
    // viewed if 2/3rds of it is in the viewport.
    repeated uint32 viewed_content_hashes = 8;

    reserved 2;
  }

  // Token used to read or write to the same storage.
  bytes consistency_token = 1;
  // ID for the next pending action.
  int32 next_action_id = 2;
  // The most recent session identifier.
  SessionID session_id = 3;
  // Schema version number. Schema versions:
  // 0: Initial version.
  // 1: Current version. Added <stream-key> to the key patterns of "content" and
  // "shared_state"
  //    records.
  int32 stream_schema_version = 4;
  repeated StreamMetadata stream_metadata = 5;
  // The GAIA ID associated with the store.
  string gaia = 6;
  // Whether WAA is enabled for this user, as reported by the last FeedQuery
  // response.
  bool web_and_app_activity_enabled = 7;
  // Whether personalization is enabled for Discover, as reported by the last
  // FeedQuery response.
  bool discover_personalization_enabled = 8;
  // Count of how many times the user has followed from the main menu, so we
  // can show appropriate user education help for the following feed.
  int32 followed_from_web_page_menu_count = 9;
  // The list of IDs representing the most recent contents viewed by the user.
  // The size of the list is capped to
  // feedstore_util::kMaxMostRecentContentHashes. The IDs are stored in the
  // ascending order of the time when the content is viewed by the user.
  repeated uint32 most_recent_viewed_content_hashes = 11;

  reserved 10;
}

// A set of StreamStructures that should be applied to a stream.
message StreamStructureSet {
  // Stream ID. Should match the id value stored in the record's key.
  string stream_key = 1;
  int32 sequence_number = 2;
  repeated StreamStructure structures = 3;
}

// This is the structure of the stream.  It is defined through the parent/child
// relationship and an operation.  This message will be journaled.  Reading
// the journal from start to end will fully define the structure of the stream.
message StreamStructure {
  // The defined set of DataOperations
  // These operations align with the Operation enum defined in
  // data_operation.proto.
  enum Operation {
    UNKNOWN = 0;
    // Clear all the content in the session, creating a new session
    CLEAR_ALL = 1;
    // Append if not present or update
    UPDATE_OR_APPEND = 2;
    // Remove the node from its parent
    REMOVE = 3;
  }
  Operation operation = 1;
  // The ContentId of the content.
  feedwire.ContentId content_id = 2;
  // The parent ContentId, or unset if this is the root.
  feedwire.ContentId parent_id = 3;

  // Type of node as denoted by the server. This type has no meaning for the
  // client.
  enum Type {
    // Default type for operations that don't affect the stream (e.g. operations
    // on shared states).
    UNKNOWN_TYPE = 0;
    // The root of the stream.
    STREAM = 1;
    // An internal tree node, which may have children.
    CARD = 2;
    // A leaf node, which provides content.
    CONTENT = 3;
    // An internal tree node, which may have children.
    GROUP = 4;
  }
  Type type = 4;
  // Set iff type=CONTENT
  ContentInfo content_info = 5;
  // Is this the root of the stream?
  bool is_root = 6;
}

message DataOperation {
  StreamStructure structure = 1;
  // Provided if structure adds content.
  Content content = 2;
}

message ContentInfo {
  // Score given by server.
  float score = 1;
  // Unix timestamp (seconds) that content was received by Chrome.
  int64 availability_time_seconds = 2;
}

message Content {
  feedwire.ContentId content_id = 1;
  // Opaque content. The UI layer knows how to parse and render this as a slice.
  bytes frame = 2;
  repeated feedwire.PrefetchMetadata prefetch_metadata = 3;
  // Stream ID. Should match the id value stored in the record's key.
  string stream_key = 4;
}

// This represents a shared state item.
message StreamSharedState {
  feedwire.ContentId content_id = 1;
  // Opaque data required to render content.
  bytes shared_state_data = 2;
  // Stream ID. Should match the id value stored in the record's key.
  string stream_key = 3;
}

// A stored action awaiting upload.
message StoredAction {
  // Unique ID for this stored action, provided by the client.
  // This is a sequential number, so that the action with the lowest id value
  // was recorded chronologically first.
  int32 id = 1;
  // How many times we have tried to upload the action.
  int32 upload_attempt_count = 2;
  // The action to upload.
  feedwire.FeedAction action = 3;
}

// List of web feeds for which the user is subscribed.
message SubscribedWebFeeds {
  repeated WebFeedInfo feeds = 1;
  // The unix timestamp in milliseconds that this data was updated from the
  // server.
  int64 update_time_millis = 2;
}

message RecommendedWebFeedIndex {
  message Entry {
    string web_feed_id = 1;
    repeated feedwire.webfeed.WebFeedMatcher matchers = 2;
  }
  repeated Entry entries = 1;
  // The unix timestamp in milliseconds that this data was updated from the
  // server.
  int64 update_time_millis = 2;
}

// Reference to an image.
message Image {
  string url = 1;
}

// See http://go/chrome-web-feed-api.
message WebFeedInfo {
  enum State {
    STATE_UNSPECIFIED = 0;
    INACTIVE = 1;
    ACTIVE = 2;
    WAITING_FOR_CONTENT = 4;
  }
  string web_feed_id = 1;
  string title = 2;
  string subtitle = 3;
  string detail_text = 4;
  string visit_uri = 5;
  string rss_uri = 6;
  Image favicon = 7;
  int64 follower_count = 8;
  State state = 9;
  repeated feedwire.webfeed.WebFeedMatcher matchers = 10;
}

message PendingWebFeedOperation {
  enum Kind {
    KIND_UNSPECIFIED = 0;
    SUBSCRIBE = 1;
    UNSUBSCRIBE = 2;
  }
  // Unique ID, for sorting operations.
  int64 id = 1;
  // The operation kind.
  Kind kind = 2;
  // The web feed ID to either subscribe or unsubscribe.
  string web_feed_id = 3;
  // Number of times the operation has been attempted.
  int32 attempts = 4;
  // Reason for this change.
  feedwire.webfeed.WebFeedChangeReason change_reason = 5;
}

message DocView {
  // Unique ID for the content that was viewed.
  uint64 docid = 1;
  // Unix timestamp when the view occurred.
  int64 view_time_millis = 4;
}