Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GO-2930: Store device names #1013

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

AnastasiaShemyakinskaya
Copy link
Member

@AnastasiaShemyakinskaya AnastasiaShemyakinskaya commented Mar 18, 2024

https://linear.app/anytype/issue/GO-2930/store-device-names

  1. Add new device object to store devices names in tech space
  2. Add RPC DeviceSetName to change device name
  3. Add RPC DeviceList to get devices list

Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
@@ -50,6 +50,7 @@ enum SmartBlockType {
FileObject = 0x215;

NotificationObject = 0x217;
DeviceObject = 0x218;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Page type is sufficient for this task, as you probably don't need special behavior for smartblock

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Contributor

@fat-fellow fat-fellow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests

…o-2930-store-device-names

# Conflicts:
#	clientlibrary/service/service.pb.go
#	core/anytype/bootstrap.go
#	pb/commands.pb.go
#	pb/service/service.pb.go
#	pkg/lib/pb/model/models.pb.go
#	pkg/lib/pb/model/protos/models.proto
Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Copy link

coderabbitai bot commented Apr 22, 2024

Walkthrough

The recent updates introduce device management capabilities within the core system. In summary:

  1. Integration of the device module for registering and handling devices,
  2. Refactoring of the isSuitableChanges function to accommodate device-specific changes,
  3. New Protobuf RPC definitions for setting device names and listing devices.

Changes

Files Change Summary
.../anytype/bootstrap.go Imported device module and registered device.NewDevices()
.../editor/smartblock.go Renamed isStoreOrNotificationChanges to isSuitableChanges and added device-related conditions
.../protos/commands.proto Added Device.SetName and Device.List message types
.../protos/service.proto Added DeviceSetName and DeviceList RPC methods in ClientCommands service definition

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Client
    participant Server
    participant DeviceManager
    
    User->>Client: Request to Set Device Name
    Client->>Server: Invoke DeviceSetName RPC
    Server->>DeviceManager: Set Device Name
    DeviceManager->>Server: Name Set Confirmation
    Server->>Client: Respond with Success
    Client->>User: Show Confirmation

    User->>Client: Request Device List
    Client->>Server: Invoke DeviceList RPC
    Server->>DeviceManager: Fetch Device List
    DeviceManager->>Server: Return Device List
    Server->>Client: Respond with Device List
    Client->>User: Display Device List

Poem

In lines of code, devices rise,
🎉 Names they earn, a sweet surprise,
From list to list, they find their place,
In servers' dance, a swift embrace.
The changes flow, like bytes that sing,
Oh what joy, these updates bring! 🚀🍃


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Comment on lines +2623 to +2641
t.Run("add device - device exist", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
st.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test",
})
newState := st.NewState()

// when
newState.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test1",
})

// then
assert.NotNil(t, st.deviceStore["id"])
assert.Equal(t, "test", st.deviceStore["id"].Name)
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an assertion to verify that the device name remains unchanged when adding an existing device.

+ assert.Equal(t, "test", newState.deviceStore["id"].Name)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
t.Run("add device - device exist", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
st.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test",
})
newState := st.NewState()
// when
newState.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test1",
})
// then
assert.NotNil(t, st.deviceStore["id"])
assert.Equal(t, "test", st.deviceStore["id"].Name)
})
t.Run("add device - device exist", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
st.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test",
})
newState := st.NewState()
// when
newState.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test1",
})
// then
assert.NotNil(t, st.deviceStore["id"])
assert.Equal(t, "test", st.deviceStore["id"].Name)
assert.Equal(t, "test", newState.deviceStore["id"].Name)
})

Comment on lines +563 to +570
- [Rpc.Device](#anytype-Rpc-Device)
- [Rpc.Device.List](#anytype-Rpc-Device-List)
- [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
- [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
- [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
- [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
- [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
- [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation of list items should be consistent with other entries.

-    - [Rpc.Device](#anytype-Rpc-Device)
-    - [Rpc.Device.List](#anytype-Rpc-Device-List)
-    - [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
-    - [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
-    - [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
-    - [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
-    - [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
-    - [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
-    - [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)
+  - [Rpc.Device](#anytype-Rpc-Device)
+  - [Rpc.Device.List](#anytype-Rpc-Device-List)
+  - [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
+  - [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
+  - [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
+  - [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
+  - [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
+  - [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
+  - [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
- [Rpc.Device](#anytype-Rpc-Device)
- [Rpc.Device.List](#anytype-Rpc-Device-List)
- [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
- [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
- [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
- [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
- [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
- [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
- [Rpc.Device](#anytype-Rpc-Device)
- [Rpc.Device.List](#anytype-Rpc-Device-List)
- [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
- [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
- [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
- [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
- [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
- [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
- [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)

Copy link

github-actions bot commented Apr 22, 2024

New Coverage 46.2% of statements
Patch Coverage 66.2% of changed statements (151/228)

Coverage provided by https://github.com/seriousben/go-patch-cover-action

…o-2930-store-device-names

# Conflicts:
#	clientlibrary/service/service.pb.go
#	docs/proto.md
#	pb/commands.pb.go
#	pb/service/service.pb.go
#	pkg/lib/pb/model/models.pb.go
#	pkg/lib/pb/model/protos/models.proto
Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 17

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 7f026fd and 2886ebb.
Files ignored due to path filters (4)
  • clientlibrary/service/service.pb.go is excluded by !**/*.pb.go
  • pb/commands.pb.go is excluded by !**/*.pb.go
  • pb/service/service.pb.go is excluded by !**/*.pb.go
  • pkg/lib/pb/model/models.pb.go is excluded by !**/*.pb.go
Files selected for processing (10)
  • core/block/editor/state/change.go (4 hunks)
  • core/block/editor/state/state.go (4 hunks)
  • core/device/service.go (1 hunks)
  • core/device/service_test.go (1 hunks)
  • core/device/store.go (1 hunks)
  • core/device/store_test.go (1 hunks)
  • docs/proto.md (10 hunks)
  • pb/protos/commands.proto (1 hunks)
  • pb/protos/service/service.proto (1 hunks)
  • pkg/lib/pb/model/protos/models.proto (5 hunks)
Additional comments not posted (23)
core/device/store.go (4)

17-25: Type definitions for Store interface and deviceStore struct are clear and well-structured.


27-29: Constructor function NewStore is correctly implemented.


31-46: Function SaveDevice correctly handles device existence checks and uses transactions effectively.


48-66: Function ListDevices is well-implemented with proper transaction management and error handling.

core/device/store_test.go (3)

12-55: Test function TestDeviceStore_SaveDevice is comprehensive and correctly tests both existing and non-existing device scenarios.


57-96: Test function TestDeviceStore_ListDevices effectively tests the scenarios of no devices and multiple devices.


98-145: Test function TestDeviceStore_UpdateDeviceName correctly handles scenarios of updating device names for both existing and non-existing devices.

core/device/service.go (6)

29-48: Type definitions for Service interface and devices struct are clear and well-structured, integrating multiple components effectively.


36-38: Constructor function NewDevices is correctly implemented with proper initialization of synchronization mechanisms.


50-60: Function Init is well-implemented, correctly setting up dependencies and initializing the store with robust error handling.


66-139: Functions Run and loadDevices are correctly implemented, effectively managing asynchronous device loading with comprehensive error handling and logging.


141-145: Function Close is correctly implemented, ensuring resource cleanup by cancelling the context.


148-184: Functions SaveDeviceInfo, UpdateName, and ListDevices are well-implemented, effectively managing device operations with appropriate error handling and integration with other services.

core/device/service_test.go (5)

24-91: Test function TestService_SaveDeviceInfo is comprehensive and correctly tests the saving of device information in both the object and the store.


93-158: Test function TestService_UpdateName effectively tests the scenarios of updating device names for both existing and non-existing devices.


160-215: Test function TestService_ListDevices correctly tests the listing of devices, handling scenarios with no devices and multiple devices effectively.


217-292: Test function TestService_loadDevices effectively tests the loading of devices from the tech space and their saving to the store, handling various scenarios appropriately.


294-317: Test function TestService_Init correctly tests the initialization and closure of the service, ensuring error-free startup and shutdown.

pb/protos/service/service.proto (2)

351-351: Ensure the DeviceSetName RPC method is implemented with appropriate request and response structures to handle device name changes effectively.

Verification successful

The DeviceSetName RPC method is implemented with appropriate request and response structures, and includes robust error handling mechanisms. The method correctly handles the device name change functionality, as evidenced by the detailed implementation in the service handling code and associated protobuf files. Here are the key points:

  • Request and Response Structures: The RpcDeviceSetNameRequest and RpcDeviceSetNameResponse are well-defined, with methods for handling protobuf operations like marshaling and unmarshaling.
  • Service Method Implementation: The method is implemented in service.pb.go and devices.go, showing proper handling of the operation with context and request parameters.
  • Error Handling: The method uses RpcDeviceSetNameResponseError to handle different error scenarios, which includes error codes and descriptions for better error reporting.

Overall, the implementation aligns with the expected functionality for changing the name of a device through the RPC method.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the implementation of `DeviceSetName` in the service handling code.

# Test: Search for the implementation of `DeviceSetName`. Expect: Proper handling of request and response.
rg --type go $'DeviceSetName'

Length of output: 12215


352-352: Verify that the DeviceList RPC method is correctly implemented to fetch a list of devices, considering potential filters and pagination.

pkg/lib/pb/model/protos/models.proto (1)

1285-1290: LGTM! The new DeviceInfo message is well-structured and aligns with the PR's objectives to enhance device management.

core/block/editor/state/state.go (2)

1977-1983: Implementation of ListDevices looks correct.

This method properly handles the traversal of state hierarchy to fetch device information, returning nil if no devices are found, which is a safe approach to handle such cases.


2033-2042: Implementation of GetDevice looks correct.

This method properly handles the retrieval of a device by its ID, correctly traversing the state hierarchy and returning nil if the device is not found.

Comment on lines +7015 to +7054
message Device {
message SetName {
message Request {
string deviceId = 1;
string name = 2;
}
message Response {
Error error = 1;
message Error {
Code code = 1;
string description = 2;

enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
}

message List {
message Request {}
message Response {
Error error = 1;
repeated anytype.model.DeviceInfo devices = 2;

message Error {
Code code = 1;
string description = 2;

enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review of New Device Management RPC Methods

  1. Device SetName RPC:

    • The SetName RPC method allows setting a new name for a device. The request and response structures are well-defined. However, consider adding more specific error codes that could handle more granular errors like DEVICE_NOT_FOUND or PERMISSION_DENIED.
  2. Device List RPC:

    • The List RPC method enables listing all devices. The response includes a list of DeviceInfo which should encapsulate all necessary device details. Ensure that the DeviceInfo model is adequately defined to include all relevant device attributes such as device type, status, etc.
- enum Code {
-     NULL = 0;
-     UNKNOWN_ERROR = 1;
-     BAD_INPUT = 2;
- }
+ enum Code {
+     NULL = 0;
+     UNKNOWN_ERROR = 1;
+     BAD_INPUT = 2;
+     DEVICE_NOT_FOUND = 3;
+     PERMISSION_DENIED = 4;
+ }

Consider adding more specific error codes to handle cases like device not found or permission issues.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
message Device {
message SetName {
message Request {
string deviceId = 1;
string name = 2;
}
message Response {
Error error = 1;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
}
message List {
message Request {}
message Response {
Error error = 1;
repeated anytype.model.DeviceInfo devices = 2;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
}
}
message Device {
message SetName {
message Request {
string deviceId = 1;
string name = 2;
}
message Response {
Error error = 1;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
DEVICE_NOT_FOUND = 3;
PERMISSION_DENIED = 4;
}
}
}
}
message List {
message Request {}
message Response {
Error error = 1;
repeated anytype.model.DeviceInfo devices = 2;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
DEVICE_NOT_FOUND = 3;
PERMISSION_DENIED = 4;
}
}
}
}
}

@@ -118,6 +118,7 @@ type State struct {
localDetails *types.Struct
relationLinks pbtypes.RelationLinks
notifications map[string]*model.Notification
deviceStore map[string]*model.DeviceInfo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add documentation for deviceStore.

It's important to document the purpose and usage of new fields in the code, especially for complex structures like State. This helps maintain code readability and ease future maintenance.

Comment on lines 848 to 874
func (s *State) makeDeviceInfoChanges() []*pb.ChangeContent {
if s.parent == nil && len(s.parent.ListDevices()) == 0 {
return nil
}
var changes []*pb.ChangeContent
for id, device := range s.deviceStore {
if d := s.parent.GetDevice(id); d != nil {
if device.Name != d.Name {
changes = append(changes, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDeviceUpdate{
DeviceUpdate: &pb.ChangeDeviceUpdate{
Id: device.Id,
Name: device.Name,
},
},
})
}
} else {
changes = append(changes, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDeviceAdd{
DeviceAdd: &pb.ChangeDeviceAdd{Device: device},
},
})
}
}
return changes
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add logging to track device changes in makeDeviceInfoChanges.

+	log.Infof("Device change processed: %s", device.Id)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
func (s *State) makeDeviceInfoChanges() []*pb.ChangeContent {
if s.parent == nil && len(s.parent.ListDevices()) == 0 {
return nil
}
var changes []*pb.ChangeContent
for id, device := range s.deviceStore {
if d := s.parent.GetDevice(id); d != nil {
if device.Name != d.Name {
changes = append(changes, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDeviceUpdate{
DeviceUpdate: &pb.ChangeDeviceUpdate{
Id: device.Id,
Name: device.Name,
},
},
})
}
} else {
changes = append(changes, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDeviceAdd{
DeviceAdd: &pb.ChangeDeviceAdd{Device: device},
},
})
}
}
return changes
}
func (s *State) makeDeviceInfoChanges() []*pb.ChangeContent {
if s.parent == nil && len(s.parent.ListDevices()) == 0 {
return nil
}
var changes []*pb.ChangeContent
for id, device := range s.deviceStore {
if d := s.parent.GetDevice(id); d != nil {
if device.Name != d.Name {
changes = append(changes, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDeviceUpdate{
DeviceUpdate: &pb.ChangeDeviceUpdate{
Id: device.Id,
Name: device.Name,
},
},
})
log.Infof("Device change processed: %s", device.Id)
}
} else {
changes = append(changes, &pb.ChangeContent{
Value: &pb.ChangeContentValueOfDeviceAdd{
DeviceAdd: &pb.ChangeDeviceAdd{Device: device},
},
})
log.Infof("Device change processed: %s", device.Id)
}
}
return changes
}

Comment on lines +19 to +20
- [Change.DeviceAdd](#anytype-Change-DeviceAdd)
- [Change.DeviceUpdate](#anytype-Change-DeviceUpdate)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct the indentation for list items to maintain consistency.

-    - [Change.DeviceAdd](#anytype-Change-DeviceAdd)
-    - [Change.DeviceUpdate](#anytype-Change-DeviceUpdate)
+  - [Change.DeviceAdd](#anytype-Change-DeviceAdd)
+  - [Change.DeviceUpdate](#anytype-Change-DeviceUpdate)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
- [Change.DeviceAdd](#anytype-Change-DeviceAdd)
- [Change.DeviceUpdate](#anytype-Change-DeviceUpdate)
- [Change.DeviceAdd](#anytype-Change-DeviceAdd)
- [Change.DeviceUpdate](#anytype-Change-DeviceUpdate)

Comment on lines +567 to +575
- [Rpc.Device](#anytype-Rpc-Device)
- [Rpc.Device.List](#anytype-Rpc-Device-List)
- [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
- [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
- [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
- [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
- [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
- [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
- [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct the indentation for list items to maintain consistency.

-    - [Rpc.Device](#anytype-Rpc-Device)
-    - [Rpc.Device.List](#anytype-Rpc-Device-List)
-    - [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
-    - [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
-    - [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
-    - [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
-    - [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
-    - [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
-    - [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)
+  - [Rpc.Device](#anytype-Rpc-Device)
+  - [Rpc.Device.List](#anytype-Rpc-Device-List)
+  - [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
+  - [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
+  - [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
+  - [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
+  - [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
+  - [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
+  - [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
- [Rpc.Device](#anytype-Rpc-Device)
- [Rpc.Device.List](#anytype-Rpc-Device-List)
- [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
- [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
- [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
- [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
- [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
- [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
- [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)
- [Rpc.Device](#anytype-Rpc-Device)
- [Rpc.Device.List](#anytype-Rpc-Device-List)
- [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request)
- [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response)
- [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error)
- [Rpc.Device.SetName](#anytype-Rpc-Device-SetName)
- [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request)
- [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response)
- [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error)

Comment on lines +2030 to +2031
| DeviceSetName | [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request) | [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response) | |
| DeviceList | [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request) | [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response) | |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove trailing spaces and ensure there are no multiple consecutive blank lines.

-| DeviceSetName | [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request) | [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response) |  |
-| DeviceList | [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request) | [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response) |  |
+| DeviceSetName | [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request) | [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response) |  
+| DeviceList | [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request) | [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response) |  

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
| DeviceSetName | [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request) | [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response) | |
| DeviceList | [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request) | [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response) | |
| DeviceSetName | [Rpc.Device.SetName.Request](#anytype-Rpc-Device-SetName-Request) | [Rpc.Device.SetName.Response](#anytype-Rpc-Device-SetName-Response) |
| DeviceList | [Rpc.Device.List.Request](#anytype-Rpc-Device-List-Request) | [Rpc.Device.List.Response](#anytype-Rpc-Device-List-Response) |

Comment on lines +2173 to +2174
| deviceAdd | [Change.DeviceAdd](#anytype-Change-DeviceAdd) | | |
| deviceUpdate | [Change.DeviceUpdate](#anytype-Change-DeviceUpdate) | | |
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure there are no multiple consecutive blank lines.

-| deviceAdd | [Change.DeviceAdd](#anytype-Change-DeviceAdd) |  |  |
-| deviceUpdate | [Change.DeviceUpdate](#anytype-Change-DeviceUpdate) |  |  |
+| deviceAdd | [Change.DeviceAdd](#anytype-Change-DeviceAdd) |  |  
+| deviceUpdate | [Change.DeviceUpdate](#anytype-Change-DeviceUpdate) |  |  

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
| deviceAdd | [Change.DeviceAdd](#anytype-Change-DeviceAdd) | | |
| deviceUpdate | [Change.DeviceUpdate](#anytype-Change-DeviceUpdate) | | |
| deviceAdd | [Change.DeviceAdd](#anytype-Change-DeviceAdd) | |
| deviceUpdate | [Change.DeviceUpdate](#anytype-Change-DeviceUpdate) | |

Comment on lines +2212 to +2242
<a name="anytype-Change-DeviceAdd"></a>

### Change.DeviceAdd



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device | [model.DeviceInfo](#anytype-model-DeviceInfo) | | |






<a name="anytype-Change-DeviceUpdate"></a>

### Change.DeviceUpdate



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | |
| name | [string](#string) | | |






Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure there are no multiple consecutive blank lines.

-<a name="anytype-Change-DeviceAdd"></a>
-### Change.DeviceAdd
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| device | [model.DeviceInfo](#anytype-model-DeviceInfo) |  |  |
-<a name="anytype-Change-DeviceUpdate"></a>
-### Change.DeviceUpdate
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| id | [string](#string) |  |  |
-| name | [string](#string) |  |  |
+<a name="anytype-Change-DeviceAdd"></a>  
+### Change.DeviceAdd  
+| Field | Type | Label | Description |  
+| ----- | ---- | ----- | ----------- |  
+| device | [model.DeviceInfo](#anytype-model-DeviceInfo) |  |  |  
+<a name="anytype-Change-DeviceUpdate"></a>  
+### Change.DeviceUpdate  
+| Field | Type | Label | Description |  
+| ----- | ---- | ----- | ----------- |  
+| id | [string](#string) |  |  |  
+| name | [string](#string) |  |  |  

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
<a name="anytype-Change-DeviceAdd"></a>
### Change.DeviceAdd
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device | [model.DeviceInfo](#anytype-model-DeviceInfo) | | |
<a name="anytype-Change-DeviceUpdate"></a>
### Change.DeviceUpdate
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | |
| name | [string](#string) | | |
<a name="anytype-Change-DeviceAdd"></a>
### Change.DeviceAdd
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| device | [model.DeviceInfo](#anytype-model-DeviceInfo) | | |
<a name="anytype-Change-DeviceUpdate"></a>
### Change.DeviceUpdate
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | |
| name | [string](#string) | | |

Comment on lines +10191 to +10309

<a name="anytype-Rpc-Device-List-Request"></a>

### Rpc.Device.List.Request







<a name="anytype-Rpc-Device-List-Response"></a>

### Rpc.Device.List.Response



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| error | [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error) | | |
| devices | [model.DeviceInfo](#anytype-model-DeviceInfo) | repeated | |






<a name="anytype-Rpc-Device-List-Response-Error"></a>

### Rpc.Device.List.Response.Error



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| code | [Rpc.Device.List.Response.Error.Code](#anytype-Rpc-Device-List-Response-Error-Code) | | |
| description | [string](#string) | | |






<a name="anytype-Rpc-Device-SetName"></a>

### Rpc.Device.SetName







<a name="anytype-Rpc-Device-SetName-Request"></a>

### Rpc.Device.SetName.Request



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| deviceId | [string](#string) | | |
| name | [string](#string) | | |






<a name="anytype-Rpc-Device-SetName-Response"></a>

### Rpc.Device.SetName.Response



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| error | [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error) | | |






<a name="anytype-Rpc-Device-SetName-Response-Error"></a>

### Rpc.Device.SetName.Response.Error



| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| code | [Rpc.Device.SetName.Response.Error.Code](#anytype-Rpc-Device-SetName-Response-Error-Code) | | |
| description | [string](#string) | | |






Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure there are no multiple consecutive blank lines.

-<a name="anytype-Rpc-Device"></a>
-### Rpc.Device
-<a name="anytype-Rpc-Device-List"></a>
-### Rpc.Device.List
-<a name="anytype-Rpc-Device-List-Request"></a>
-### Rpc.Device.List.Request
-<a name="anytype-Rpc-Device-List-Response"></a>
-### Rpc.Device.List.Response
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| error | [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error) |  |  |
-| devices | [model.DeviceInfo](#anytype-model-DeviceInfo) | repeated |  |
-<a name="anytype-Rpc-Device-List-Response-Error"></a>
-### Rpc.Device.List.Response.Error
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| code | [Rpc.Device.List.Response.Error.Code](#anytype-Rpc-Device-List-Response-Error-Code) |  |  |
-| description | [string](#string) |  |  |
-<a name="anytype-Rpc-Device-SetName"></a>
-### Rpc.Device.SetName
-<a name="anytype-Rpc-Device-SetName-Request"></a>
-### Rpc.Device.SetName.Request
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| deviceId | [string](#string) |  |  |
-| name | [string](#string) |  |  |
-<a name="anytype-Rpc-Device-SetName-Response"></a>
-### Rpc.Device.SetName.Response
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| error | [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error) |  |  |
-<a name="anytype-Rpc-Device-SetName-Response-Error"></a>
-### Rpc.Device.SetName.Response.Error
-| Field | Type | Label | Description |
-| ----- | ---- | ----- | ----------- |
-| code | [Rpc.Device.SetName.Response.Error.Code](#anytype-Rpc-Device-SetName-Response-Error-Code) |  |  |
-| description | [string](#string) |  |  |
+<a name="anytype-Rpc-Device"></a>  
+### Rpc.Device  
+<a name="anytype-Rpc-Device-List"></a>  
+### Rpc.Device.List  
+<a name="anytype-Rpc-Device-List-Request"></a>  
+### Rpc.Device.List.Request  
+<a name="anytype-Rpc-Device-List-Response"></a>  
+### Rpc.Device.List.Response  
+| Field | Type | Label | Description |  
+| ----- | ---- | ----- | ----------- |  
+| error | [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error) |  |  |  
+| devices | [model.DeviceInfo](#anytype-model-DeviceInfo) | repeated |  |  
+<a name="anytype-Rpc-Device-List-Response-Error"></a>  
+### Rpc.Device.List.Response.Error  
+| Field | Type | Label | Description |  
+| ----- | ---- | ----- | ----------- |  
+| code | [Rpc.Device.List.Response.Error.Code](#anytype-Rpc-Device-List-Response-Error-Code) |  |  |  
+| description | [string](#string) |  |  |  
+<a name="anytype-Rpc-Device-SetName"></a>  
+### Rpc.Device.SetName  
+<a name="anytype-Rpc-Device-SetName-Request"></a>  
+### Rpc.Device.SetName.Request  
+| Field | Type | Label | Description |  
+| ----- | ---- | ----- | ----------- |  
+| deviceId | [string](#string) |  |  |  
+| name | [string](#string) |  |  |  
+<a name="anytype-Rpc-Device-SetName-Response"></a>  
+### Rpc.Device.SetName.Response  
+| Field | Type | Label | Description |  
+| ----- | ---- | ----- | ----------- |  
+| error | [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error) |  |  |  
+<a name="anytype-Rpc-Device-SetName-Response-Error"></a>  
+### Rpc.Device.SetName.Response.Error  
+| Field | Type | Label | Description |  
+| ----- | ---- | ----- | ----------- |  
+| code | [Rpc.Device.SetName.Response.Error.Code](#anytype-Rpc-Device-SetName-Response-Error-Code) |  |  |  
+| description | [string](#string) |  |  |  

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
<a name="anytype-Rpc-Device"></a>
### Rpc.Device
<a name="anytype-Rpc-Device-List"></a>
### Rpc.Device.List
<a name="anytype-Rpc-Device-List-Request"></a>
### Rpc.Device.List.Request
<a name="anytype-Rpc-Device-List-Response"></a>
### Rpc.Device.List.Response
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| error | [Rpc.Device.List.Response.Error](#anytype-Rpc-Device-List-Response-Error) | | |
| devices | [model.DeviceInfo](#anytype-model-DeviceInfo) | repeated | |
<a name="anytype-Rpc-Device-List-Response-Error"></a>
### Rpc.Device.List.Response.Error
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| code | [Rpc.Device.List.Response.Error.Code](#anytype-Rpc-Device-List-Response-Error-Code) | | |
| description | [string](#string) | | |
<a name="anytype-Rpc-Device-SetName"></a>
### Rpc.Device.SetName
<a name="anytype-Rpc-Device-SetName-Request"></a>
### Rpc.Device.SetName.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| deviceId | [string](#string) | | |
| name | [string](#string) | | |
<a name="anytype-Rpc-Device-SetName-Response"></a>
### Rpc.Device.SetName.Response
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| error | [Rpc.Device.SetName.Response.Error](#anytype-Rpc-Device-SetName-Response-Error) | | |
<a name="anytype-Rpc-Device-SetName-Response-Error"></a>
### Rpc.Device.SetName.Response.Error
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| code | [Rpc.Device.SetName.Response.Error.Code](#anytype-Rpc-Device-SetName-Response-Error-Code) | | |
| description | [string](#string) | | |

Comment on lines +20128 to +20153
<a name="anytype-Rpc-Device-List-Response-Error-Code"></a>

### Rpc.Device.List.Response.Error.Code


| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | |
| UNKNOWN_ERROR | 1 | |
| BAD_INPUT | 2 | |



<a name="anytype-Rpc-Device-SetName-Response-Error-Code"></a>

### Rpc.Device.SetName.Response.Error.Code


| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | |
| UNKNOWN_ERROR | 1 | |
| BAD_INPUT | 2 | |



Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure there are no multiple consecutive blank lines.

-<a name="anytype-Rpc-Device-List-Response-Error-Code"></a>
-### Rpc.Device.List.Response.Error.Code
-| Name | Number | Description |
-| ---- | ------ | ----------- |
-| NULL | 0 |  |
-| UNKNOWN_ERROR | 1 |  |
-| BAD_INPUT | 2 |  |
-<a name="anytype-Rpc-Device-SetName-Response-Error-Code"></a>
-### Rpc.Device.SetName.Response.Error.Code
-| Name | Number | Description |
-| ---- | ------ | ----------- |
-| NULL | 0 |  |
-| UNKNOWN_ERROR | 1 |  |
-| BAD_INPUT | 2 |  |
+<a name="anytype-Rpc-Device-List-Response-Error-Code"></a>  
+### Rpc.Device.List.Response.Error.Code  
+| Name | Number | Description |  
+| ---- | ------ | ----------- |  
+| NULL | 0 |  |  
+| UNKNOWN_ERROR | 1 |  |  
+| BAD_INPUT | 2 |  |  
+<a name="anytype-Rpc-Device-SetName-Response-Error-Code"></a>  
+### Rpc.Device.SetName.Response.Error.Code  
+| Name | Number | Description |  
+| ---- | ------ | ----------- |  
+| NULL | 0 |  |  
+| UNKNOWN_ERROR | 1 |  |  
+| BAD_INPUT | 2 |  |  

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
<a name="anytype-Rpc-Device-List-Response-Error-Code"></a>
### Rpc.Device.List.Response.Error.Code
| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | |
| UNKNOWN_ERROR | 1 | |
| BAD_INPUT | 2 | |
<a name="anytype-Rpc-Device-SetName-Response-Error-Code"></a>
### Rpc.Device.SetName.Response.Error.Code
| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | |
| UNKNOWN_ERROR | 1 | |
| BAD_INPUT | 2 | |
<a name="anytype-Rpc-Device-List-Response-Error-Code"></a>
### Rpc.Device.List.Response.Error.Code
| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | |
| UNKNOWN_ERROR | 1 | |
| BAD_INPUT | 2 | |
<a name="anytype-Rpc-Device-SetName-Response-Error-Code"></a>
### Rpc.Device.SetName.Response.Error.Code
| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | |
| UNKNOWN_ERROR | 1 | |
| BAD_INPUT | 2 | |

Comment on lines 1329 to 1333
func hasChanges(changes []*pb.ChangeContent) bool {
for _, ch := range changes {
if isStoreOrNotificationChanges(ch) {
if isSuitableChanges(ch) {
return true
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear from the name of the func what hasChanges actually does. It's in the context of the sb package, not notifications

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can rename hasChanges to something like hasChangesToPush, because we can check such changes in that function: store, notifications, devices changes

@@ -823,6 +845,34 @@ func (s *State) makeNotificationChanges() []*pb.ChangeContent {
return changes
}

func (s *State) makeDeviceInfoChanges() []*pb.ChangeContent {
if s.parent == nil && len(s.parent.ListDevices()) == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Nil deref here(in case s.parent is nil)
  2. Also for the first change should it work fine if the parent is nil but we have devices in the current state?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed and add test

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 2886ebb and 4ba4458.
Files ignored due to path filters (4)
  • clientlibrary/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • docs/proto.md is excluded by !**/proto.md
  • pb/commands.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • pb/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
Files selected for processing (6)
  • core/anytype/bootstrap.go (2 hunks)
  • core/block/editor/smartblock/smartblock.go (1 hunks)
  • core/block/editor/state/state.go (4 hunks)
  • core/block/editor/state/state_test.go (1 hunks)
  • pb/protos/commands.proto (1 hunks)
  • pb/protos/service/service.proto (1 hunks)
Additional comments not posted (11)
core/anytype/bootstrap.go (2)

56-56: Ensure the new device package is correctly integrated and used within the application.


286-286: The registration of NewDevices() from the device package is a crucial part of integrating the new device management functionality. Verify that the NewDevices() function initializes all necessary components and adheres to the expected lifecycle management (initialization, running, and closure) as outlined in the PR objectives.

pb/protos/service/service.proto (1)

352-353: The addition of the DeviceSetName and DeviceList RPC methods is aligned with the PR objectives to enhance device management capabilities. Ensure that these methods are implemented with the correct request and response types and that they integrate seamlessly with the existing service architecture.

core/block/editor/state/state.go (4)

121-121: Add documentation for deviceStore.


2002-2017: Clarify behavior when adding an existing device.


2019-2040: Consider handling the case where a device does not exist.


1986-1992: The implementation of ListDevices correctly handles cases where no device information is available by returning nil. This is a safe and expected behavior in Go.

core/block/editor/state/state_test.go (4)

2614-2632: The existing comment is still valid and correctly suggests adding an assertion to ensure the device name remains unchanged when adding an existing device.


2635-2673: The tests for GetDevice method are comprehensive and cover various scenarios including non-existent and existent device retrieval.


2676-2701: The tests for ListDevices method are comprehensive and cover scenarios with no devices and with devices present.


2614-2632: Consider adding a test to ensure that adding a device with an existing ID does not overwrite the existing device's details unless explicitly intended.

Verification successful

The implementation of the AddDevice function in core/block/editor/state/state.go confirms that if a device with the same ID already exists in the deviceStore, the function returns early without overwriting the existing device's details. This behavior is consistent with the concern raised in the review comment.

Additionally, the test case add device - device exist in core/block/editor/state/state_test.go verifies this behavior by asserting that the existing device's details are not overwritten when a device with the same ID is added.

Therefore, the current implementation and test coverage already address the concern mentioned in the review comment.

  • core/block/editor/state/state.go:
    • The AddDevice function checks if a device with the same ID exists and returns early if it does, preventing overwriting.
  • core/block/editor/state/state_test.go:
    • The test case add device - device exist ensures that adding a device with an existing ID does not overwrite the existing device's details.
Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that adding a device with an existing ID does not overwrite the existing device's details.
# Test: Search for the function usage. Expect: Only occurances of the new signature.
rg --type go $'AddDevice'

Length of output: 1054



Script:

#!/bin/bash
# Retrieve the implementation of the AddDevice function in core/block/editor/state/state.go
ast-grep --lang go --pattern $'func (s *State) AddDevice(device *model.DeviceInfo) {
  $$$
}' --json

# Retrieve the test cases in core/block/editor/state/state_test.go that involve AddDevice
ast-grep --lang go --pattern $'func TestState_AddDevice(t *testing.T) {
  $$$
}' --json

Length of output: 3259

Comment on lines +1323 to +1337
if isSuitableChanges(ch) {
return true
}
}
return false
}

func isStoreOrNotificationChanges(ch *pb.ChangeContent) bool {
func isSuitableChanges(ch *pb.ChangeContent) bool {
return ch.GetStoreKeySet() != nil ||
ch.GetStoreKeyUnset() != nil ||
ch.GetStoreSliceUpdate() != nil ||
ch.GetNotificationCreate() != nil ||
ch.GetNotificationUpdate() != nil
ch.GetNotificationUpdate() != nil ||
ch.GetDeviceUpdate() != nil ||
ch.GetDeviceAdd() != nil
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify the purpose of isSuitableChanges function.

The function isSuitableChanges checks various conditions to determine if a change is "suitable". However, the name of the function and its implementation are not immediately clear, especially in the context of the smart block package. Consider renaming this function to more accurately reflect its purpose, such as hasRelevantChangeTypes, and ensure that the function's documentation clearly describes what makes a change "suitable".

Comment on lines +7046 to +7063
message List {
message Request {}
message Response {
Error error = 1;
repeated anytype.model.DeviceInfo devices = 2;

message Error {
Code code = 1;
string description = 2;

enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding more specific error codes for Device.List.

 enum Code {
     NULL = 0;
     UNKNOWN_ERROR = 1;
     BAD_INPUT = 2;
+    NO_DEVICES_FOUND = 3;
 }

This addition will help handle cases where no devices are found, providing clearer feedback to the user.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
message List {
message Request {}
message Response {
Error error = 1;
repeated anytype.model.DeviceInfo devices = 2;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
}
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
NO_DEVICES_FOUND = 3;
}

Comment on lines +7025 to +7043
message Device {
message SetName {
message Request {
string deviceId = 1;
string name = 2;
}
message Response {
Error error = 1;
message Error {
Code code = 1;
string description = 2;

enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding more specific error codes for Device.SetName.

 enum Code {
     NULL = 0;
     UNKNOWN_ERROR = 1;
     BAD_INPUT = 2;
+    DEVICE_NOT_FOUND = 3;
+    PERMISSION_DENIED = 4;
 }

This addition will help handle cases where the device is not found or the user does not have the necessary permissions to change the device name.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
message Device {
message SetName {
message Request {
string deviceId = 1;
string name = 2;
}
message Response {
Error error = 1;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
}
}
}
enum Code {
NULL = 0;
UNKNOWN_ERROR = 1;
BAD_INPUT = 2;
DEVICE_NOT_FOUND = 3;
PERMISSION_DENIED = 4;
}

Comment on lines +2019 to +2040
func (s *State) SetDeviceName(id, name string) {
if s.deviceStore == nil {
s.deviceStore = map[string]*model.DeviceInfo{}
}
if s.parent != nil {
for _, d := range s.parent.ListDevices() {
if _, ok := s.deviceStore[d.Id]; !ok {
s.deviceStore[d.Id] = pbtypes.CopyDevice(d)
}
}
}
if _, ok := s.deviceStore[id]; !ok {
device := &model.DeviceInfo{
Id: id,
Name: name,
AddDate: time.Now().Unix(),
}
s.deviceStore[id] = device
return
}
s.deviceStore[id].Name = name
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior of SetDeviceName might be unexpected as it creates a new device if one does not exist. Consider adding error handling or a return value to inform the caller about the creation of a new device.

- func (s *State) SetDeviceName(id, name string) {
+ func (s *State) SetDeviceName(id, name string) error {
    if s.deviceStore == nil {
        s.deviceStore = map[string]*model.DeviceInfo{}
    }
    if _, ok := s.deviceStore[id]; !ok {
        device := &model.DeviceInfo{
            Id:      id,
            Name:    name,
            AddDate: time.Now().Unix(),
        }
        s.deviceStore[id] = device
-       return
+       return fmt.Errorf("device created as it did not exist")
    }
    s.deviceStore[id].Name = name
+   return nil
}

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
func (s *State) SetDeviceName(id, name string) {
if s.deviceStore == nil {
s.deviceStore = map[string]*model.DeviceInfo{}
}
if s.parent != nil {
for _, d := range s.parent.ListDevices() {
if _, ok := s.deviceStore[d.Id]; !ok {
s.deviceStore[d.Id] = pbtypes.CopyDevice(d)
}
}
}
if _, ok := s.deviceStore[id]; !ok {
device := &model.DeviceInfo{
Id: id,
Name: name,
AddDate: time.Now().Unix(),
}
s.deviceStore[id] = device
return
}
s.deviceStore[id].Name = name
}
func (s *State) SetDeviceName(id, name string) error {
if s.deviceStore == nil {
s.deviceStore = map[string]*model.DeviceInfo{}
}
if s.parent != nil {
for _, d := range s.parent.ListDevices() {
if _, ok := s.deviceStore[d.Id]; !ok {
s.deviceStore[d.Id] = pbtypes.CopyDevice(d)
}
}
}
if _, ok := s.deviceStore[id]; !ok {
device := &model.DeviceInfo{
Id: id,
Name: name,
AddDate: time.Now().Unix(),
}
s.deviceStore[id] = device
return fmt.Errorf("device created as it did not exist")
}
s.deviceStore[id].Name = name
return nil
}

Comment on lines +2002 to +2017
func (s *State) AddDevice(device *model.DeviceInfo) {
if s.deviceStore == nil {
s.deviceStore = map[string]*model.DeviceInfo{}
}
if s.parent != nil {
for _, d := range s.parent.ListDevices() {
if _, ok := s.deviceStore[d.Id]; !ok {
s.deviceStore[d.Id] = pbtypes.CopyDevice(d)
}
}
}
if _, ok := s.deviceStore[device.Id]; ok {
return
}
s.deviceStore[device.Id] = device
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider modifying AddDevice to return a boolean indicating whether the addition was successful. This can help callers handle cases where the device already exists more gracefully.

- func (s *State) AddDevice(device *model.DeviceInfo) {
+ func (s *State) AddDevice(device *model.DeviceInfo) bool {
    if s.deviceStore == nil {
        s.deviceStore = map[string]*model.DeviceInfo{}
    }
    if _, ok := s.deviceStore[device.Id]; ok {
-       return
+       return false
    }
    s.deviceStore[device.Id] = device
+   return true
}

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
func (s *State) AddDevice(device *model.DeviceInfo) {
if s.deviceStore == nil {
s.deviceStore = map[string]*model.DeviceInfo{}
}
if s.parent != nil {
for _, d := range s.parent.ListDevices() {
if _, ok := s.deviceStore[d.Id]; !ok {
s.deviceStore[d.Id] = pbtypes.CopyDevice(d)
}
}
}
if _, ok := s.deviceStore[device.Id]; ok {
return
}
s.deviceStore[device.Id] = device
}
func (s *State) AddDevice(device *model.DeviceInfo) bool {
if s.deviceStore == nil {
s.deviceStore = map[string]*model.DeviceInfo{}
}
if s.parent != nil {
for _, d := range s.parent.ListDevices() {
if _, ok := s.deviceStore[d.Id]; !ok {
s.deviceStore[d.Id] = pbtypes.CopyDevice(d)
}
}
}
if _, ok := s.deviceStore[device.Id]; ok {
return false
}
s.deviceStore[device.Id] = device
return true
}

Comment on lines +2703 to +2732
func TestState_SetDeviceName(t *testing.T) {
t.Run("set device name, device not exist", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)

// when
st.SetDeviceName("id", "test")

// then
assert.NotNil(t, st.deviceStore["id"])
assert.Equal(t, st.deviceStore["id"].Name, "test")
})

t.Run("set device name, device exists", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
st.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test",
})

newState := st.NewState()
// when
newState.SetDeviceName("id", "test1")

// then
assert.NotNil(t, newState.deviceStore["id"])
assert.Equal(t, newState.deviceStore["id"].Name, "test1")
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider modifying the behavior of SetDeviceName to avoid creating a new device if it does not exist, as this could lead to unintended side effects.

- assert.NotNil(t, st.deviceStore["id"])
- assert.Equal(t, st.deviceStore["id"].Name, "test")
+ assert.Nil(t, st.deviceStore["id"])

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
func TestState_SetDeviceName(t *testing.T) {
t.Run("set device name, device not exist", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
// when
st.SetDeviceName("id", "test")
// then
assert.NotNil(t, st.deviceStore["id"])
assert.Equal(t, st.deviceStore["id"].Name, "test")
})
t.Run("set device name, device exists", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
st.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test",
})
newState := st.NewState()
// when
newState.SetDeviceName("id", "test1")
// then
assert.NotNil(t, newState.deviceStore["id"])
assert.Equal(t, newState.deviceStore["id"].Name, "test1")
})
}
func TestState_SetDeviceName(t *testing.T) {
t.Run("set device name, device not exist", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
// when
st.SetDeviceName("id", "test")
// then
assert.Nil(t, st.deviceStore["id"])
})
t.Run("set device name, device exists", func(t *testing.T) {
// given
st := NewDoc("root", nil).(*State)
st.AddDevice(&model.DeviceInfo{
Id: "id",
Name: "test",
})
newState := st.NewState()
// when
newState.SetDeviceName("id", "test1")
// then
assert.NotNil(t, newState.deviceStore["id"])
assert.Equal(t, newState.deviceStore["id"].Name, "test1")
})
}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Outside diff range and nitpick comments (2)
pkg/lib/pb/model/protos/models.proto (2)

Line range hint 1196-1213: Add documentation for new Membership.Status enum values.

It's good practice to document the purpose and use-case of each enum value to aid understanding and maintenance. Consider adding comments explaining when each status should be used.


1213-1213: Ensure consistency in enum naming conventions.

The PaymentMethod enum uses a prefix Method which is redundant since it's already within an enum named PaymentMethod. Consider simplifying the names to None, Stripe, Crypto, InappApple, and InappGoogle for clarity and consistency.

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between 4ba4458 and ad376a5.
Files ignored due to path filters (5)
  • clientlibrary/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • docs/proto.md is excluded by !**/proto.md
  • pb/commands.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • pb/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • pkg/lib/pb/model/models.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
Files selected for processing (6)
  • core/block/editor/smartblock/smartblock.go (2 hunks)
  • core/block/editor/state/change.go (4 hunks)
  • core/block/editor/state/change_test.go (1 hunks)
  • pb/protos/commands.proto (1 hunks)
  • pb/protos/service/service.proto (1 hunks)
  • pkg/lib/pb/model/protos/models.proto (5 hunks)
Files skipped from review as they are similar to previous changes (3)
  • core/block/editor/smartblock/smartblock.go
  • pb/protos/commands.proto
  • pb/protos/service/service.proto
Additional comments not posted (8)
core/block/editor/state/change_test.go (5)

811-881: Review of TestRootDeviceChanges:

  1. No Changes Test: Validates no changes occur with an empty state. This is a good baseline test.
  2. Add New Device Test: Checks the addition of a new device. It correctly asserts the changes length and the device added.
  3. Update Device Test: Verifies updating a device's name. It properly checks the change and updated name.
  4. Add Device - Parent Nil Test: Tests adding a device when the parent is nil. This scenario is less typical and should be documented why it's important to test this edge case.

Line range hint 32-58: Review of TestState_ChangesCreate_MoveAdd:

  • This test effectively checks the movement and addition of blocks within a state. It uses assertions to verify the correct number of changes and the specific types of changes.
  • The use of require for preconditions and assert for postconditions is correctly applied.

Line range hint 60-71: Review of TestState_ChangesCreate_Collection_Set:

  • The test correctly sets a value in the state's store and checks the resulting changes.
  • The assertion comparing the change's string representation is a robust way to ensure the change is exactly as expected.

Line range hint 73-84: Review of TestState_ChangesCreate_Collection_Unset:

  • This test effectively checks the removal of a value from the state's store.
  • The use of require.NoError to ensure no errors occur during the state application is appropriate.

Line range hint 86-142: Review of TestState_ChangesCreate_StoreSlice:

  • Comprehensive testing of store slice operations (add, remove, move).
  • The structured approach using table-driven tests enhances maintainability and clarity.
  • Each scenario is well-documented with comments, and the assertions are thorough.
core/block/editor/state/change.go (1)

Line range hint 634-874: Review the logic for generating device info changes.

The method makeDeviceInfoChanges is crucial for handling device updates and additions. It's important to verify that this method handles all edge cases correctly, especially in scenarios where devices are updated or added.

pkg/lib/pb/model/protos/models.proto (2)

Line range hint 1255-1273: Review the new fields in MembershipTierData.

The new fields and enum values in MembershipTierData seem well-defined and relevant to the functionality described in the PR. Ensure that all new fields are properly integrated and tested in the system.


1301-1306: Validate the new DeviceInfo message structure.

The structure of the new DeviceInfo message looks appropriate for storing device-related information. Ensure that all fields are used effectively and that the data integrity is maintained when devices are added, updated, or queried.

Comment on lines +473 to +481
func (s *State) updateDevice(update *pb.ChangeDeviceUpdate) {
if s.deviceStore == nil {
return
}
if _, ok := s.deviceStore[update.Id]; !ok {
return
}
s.deviceStore[update.Id].Name = update.Name
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enhance error handling and logging in updateDevice.

+	if _, ok := s.deviceStore[update.Id]; !ok {
+		log.Errorf("Device not found: %s", update.Id)
+		return fmt.Errorf("device not found: %s", update.Id)
+	}
+	log.Infof("Device updated: %s", update.Id)

Improving error handling in the updateDevice method ensures that updates are only applied to existing devices, and provides logging for both error and normal cases, enhancing traceability and error diagnosis.

Committable suggestion was skipped due low confidence.

Comment on lines +466 to +471
func (s *State) addDevice(deviceInfo *model.DeviceInfo) {
if s.deviceStore == nil {
s.deviceStore = map[string]*model.DeviceInfo{}
}
s.deviceStore[deviceInfo.Id] = deviceInfo
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding error handling and logging for addDevice.

+	if err := validateDeviceInfo(deviceInfo); err != nil {
+		log.Errorf("Invalid device info: %v", err)
+		return err
+	}

Adding error handling and logging in the addDevice method can help identify issues with device information at the time of addition, improving the robustness of device management.

Committable suggestion was skipped due low confidence.

Comment on lines +253 to +256
case ch.GetDeviceAdd() != nil:
s.addDevice(ch.GetDeviceAdd().GetDevice())
case ch.GetDeviceUpdate() != nil:
s.updateDevice(ch.GetDeviceUpdate())
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling for device-related changes.

+	if err := s.validateDevice(ch.GetDeviceAdd().GetDevice()); err != nil {
+		return fmt.Errorf("failed to add device: %v", err)
+	}
+	if err := s.validateDeviceUpdate(ch.GetDeviceUpdate()); err != nil {
+		return fmt.Errorf("failed to update device: %v", err)
+	}

Consider adding error handling to ensure that device additions and updates are validated before they are processed. This can help prevent issues related to invalid device data being added or updated in the state.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
case ch.GetDeviceAdd() != nil:
s.addDevice(ch.GetDeviceAdd().GetDevice())
case ch.GetDeviceUpdate() != nil:
s.updateDevice(ch.GetDeviceUpdate())
case ch.GetDeviceAdd() != nil:
if err := s.validateDevice(ch.GetDeviceAdd().GetDevice()); err != nil {
return fmt.Errorf("failed to add device: %v", err)
}
s.addDevice(ch.GetDeviceAdd().GetDevice())
case ch.GetDeviceUpdate() != nil:
if err := s.validateDeviceUpdate(ch.GetDeviceUpdate()); err != nil {
return fmt.Errorf("failed to update device: %v", err)
}
s.updateDevice(ch.GetDeviceUpdate())

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between ad376a5 and c3784fd.
Files ignored due to path filters (2)
  • docs/proto.md is excluded by !**/proto.md
  • pb/commands.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
Files selected for processing (1)
  • pb/protos/commands.proto (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • pb/protos/commands.proto

…o-2930-store-device-names

# Conflicts:
#	clientlibrary/service/service.pb.go
#	pb/commands.pb.go
#	pb/service/service.pb.go
#	pkg/lib/pb/model/models.pb.go
Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between c3784fd and c8db938.

Files ignored due to path filters (5)
  • clientlibrary/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • docs/proto.md is excluded by !**/proto.md
  • pb/commands.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • pb/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • pkg/lib/pb/model/models.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
Files selected for processing (3)
  • pb/protos/commands.proto (1 hunks)
  • pb/protos/service/service.proto (1 hunks)
  • pkg/lib/pb/model/protos/models.proto (5 hunks)
Files skipped from review as they are similar to previous changes (3)
  • pb/protos/commands.proto
  • pb/protos/service/service.proto
  • pkg/lib/pb/model/protos/models.proto

…o-2930-store-device-names

# Conflicts:
#	pb/commands.pb.go
#	pkg/lib/pb/model/models.pb.go
Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between c8db938 and 1a98f6a.

Files ignored due to path filters (3)
  • docs/proto.md is excluded by !**/proto.md
  • pb/commands.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • pkg/lib/pb/model/models.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
Files selected for processing (2)
  • pb/protos/commands.proto (1 hunks)
  • pkg/lib/pb/model/protos/models.proto (5 hunks)
Files skipped from review as they are similar to previous changes (2)
  • pb/protos/commands.proto
  • pkg/lib/pb/model/protos/models.proto

Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Outside diff range and nitpick comments (1)
core/device/service.go (1)

29-34: Ensure the Service interface is well-documented.

Adding documentation comments for the Service interface would improve code maintainability and clarity, especially for new developers or external contributors.

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 1a98f6a and 400d64d.

Files selected for processing (1)
  • core/device/service.go (1 hunks)
Additional comments not posted (1)
core/device/service.go (1)

183-186: Verify the synchronization mechanism in ListDevices.

Ensure that the finishLoad channel is correctly synchronized across all operations that depend on device loading.

Verification successful

To verify the synchronization mechanism of the finishLoad channel in the ListDevices method, we need to examine the context around its usage. Specifically, we should look at the initialization, closing, and waiting on this channel to ensure there are no synchronization issues.


To ensure proper synchronization of the finishLoad channel, we need to correct the regex error and gather the necessary context around its initialization, defer close, and waiting.


To ensure proper synchronization of the finishLoad channel, we need to simplify the regex pattern and gather the necessary context around its initialization, defer close, and waiting.


To ensure proper synchronization of the finishLoad channel, we need to re-run the search for the defer close statement and gather the necessary context.


To ensure proper synchronization of the finishLoad channel, we need to search for any close statements for the finishLoad channel to gather the necessary context.


To ensure proper synchronization of the finishLoad channel, we need to search for any other potential mechanisms that might close the finishLoad channel.


The finishLoad channel is properly synchronized in the ListDevices method. The channel is initialized in the NewDevices function and closed in the loadDevices method using a defer statement. This ensures that the channel is closed once the device loading process is complete, preventing any potential deadlocks or race conditions.

  • finishLoad is initialized in the NewDevices function.
  • finishLoad is closed in the loadDevices method using defer close(d.finishLoad).
  • ListDevices waits on finishLoad to ensure devices are loaded before proceeding.
Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Check for proper synchronization of `finishLoad` channel in device loading.

# Test: Search for all usages of `finishLoad`. Expect: Proper synchronization without deadlocks.
rg --type go $'finishLoad'

Length of output: 485



Script:

#!/bin/bash
# Description: Gather context around the usage of `finishLoad` channel to ensure proper synchronization.

# Find the initialization of the `finishLoad` channel.
rg --context 5 'finishLoad: make(chan struct{})' core/device/service.go

# Find the defer close statement for the `finishLoad` channel.
rg --context 5 'defer close(d.finishLoad)' core/device/service.go

# Find the waiting on the `finishLoad` channel.
rg --context 5 '<-d.finishLoad' core/device/service.go

Length of output: 500



Script:

#!/bin/bash
# Description: Gather context around the usage of `finishLoad` channel to ensure proper synchronization.

# Find the initialization of the `finishLoad` channel.
rg --context 5 'finishLoad:\s*make\(chan struct{}\)' core/device/service.go

# Find the defer close statement for the `finishLoad` channel.
rg --context 5 'defer close(d.finishLoad)' core/device/service.go

# Find the waiting on the `finishLoad` channel.
rg --context 5 '<-d.finishLoad' core/device/service.go

Length of output: 511



Script:

#!/bin/bash
# Description: Gather context around the usage of `finishLoad` channel to ensure proper synchronization.

# Find the initialization of the `finishLoad` channel.
rg --context 5 'finishLoad: make' core/device/service.go

# Find the defer close statement for the `finishLoad` channel.
rg --context 5 'defer close(d.finishLoad)' core/device/service.go

# Find the waiting on the `finishLoad` channel.
rg --context 5 '<-d.finishLoad' core/device/service.go

Length of output: 633



Script:

#!/bin/bash
# Description: Gather context around the usage of `finishLoad` channel to ensure proper synchronization.

# Find the defer close statement for the `finishLoad` channel.
rg --context 10 'defer close(d.finishLoad)' core/device/service.go

Length of output: 68



Script:

#!/bin/bash
# Description: Gather context around the usage of `finishLoad` channel to ensure proper synchronization.

# Find any close statements for the `finishLoad` channel.
rg --context 10 'close(d.finishLoad)' core/device/service.go

Length of output: 62



Script:

#!/bin/bash
# Description: Gather context around the usage of `finishLoad` channel to ensure proper synchronization.

# Find any references to `finishLoad` to identify potential mechanisms that might close it.
rg --context 10 'finishLoad' core/device/service.go

Length of output: 1878

Comment on lines +36 to +38
func NewDevices() Service {
return &devices{finishLoad: make(chan struct{})}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialization of devices struct can be optimized.

Consider initializing all fields of devices struct explicitly in NewDevices function to enhance code readability and prevent future errors related to uninitialized fields.

Comment on lines +73 to +140
func (d *devices) loadDevices(ctx context.Context) {
defer close(d.finishLoad)
uk, err := domain.NewUniqueKey(sb.SmartBlockTypePage, "")
if err != nil {
log.Errorf("failed to get devices object unique key: %v", err)
return
}
techSpace, err := d.spaceService.GetTechSpace(ctx)
if err != nil {
return
}
deviceObject, err := techSpace.DeriveTreeObject(ctx, objectcache.TreeDerivationParams{
Key: uk,
InitFunc: func(id string) *smartblock.InitContext {
return &smartblock.InitContext{
Ctx: ctx,
SpaceID: techSpace.Id(),
State: state.NewDoc(id, nil).(*state.State),
}
},
})
if err != nil && !errors.Is(err, treestorage.ErrTreeExists) {
log.Errorf("failed to derive device object: %v", err)
return
}
if err == nil {
d.deviceObjectId = deviceObject.Id()
}
if errors.Is(err, treestorage.ErrTreeExists) {
id, err := techSpace.DeriveObjectID(ctx, uk)
if err != nil {
log.Errorf("failed to derive device object id: %v", err)
return
}
d.deviceObjectId = id
}
if deviceObject == nil {
deviceObject, err = techSpace.GetObject(ctx, d.deviceObjectId)
if err != nil {
log.Errorf("failed to get device object id: %v", err)
return
}
}
hostname, err := os.Hostname()
if err != nil {
log.Errorf("failed to get hostname: %v", err)
return
}
deviceObject.Lock()
st := deviceObject.NewState()
deviceId := d.wallet.GetDevicePrivkey().GetPublic().PeerId()
st.AddDevice(&model.DeviceInfo{
Id: deviceId,
Name: hostname,
AddDate: time.Now().Unix(),
IsConnected: true,
})
err = deviceObject.Apply(st)
if err != nil {
log.Errorf("failed to apply device state: %v", err)
}
deviceObject.Unlock()
for _, info := range st.ListDevices() {
err := d.store.SaveDevice(info)
if err != nil {
log.Errorf("failed to save device: %v", err)
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize loadDevices method for better error handling and efficiency.

  1. Consolidate error handling to reduce redundancy and improve readability.
  2. Use a single error handling block for the entire method.
  3. Consider using early returns for error conditions to reduce nesting and improve readability.

Comment on lines +150 to +165
func (d *devices) SaveDeviceInfo(ctx context.Context, device *model.DeviceInfo) error {
err := d.store.SaveDevice(device)
if err != nil {
return fmt.Errorf("failed to save device: %w", err)
}

spc, err := d.spaceService.Get(ctx, d.spaceService.TechSpaceId())
if err != nil {
return fmt.Errorf("failed to get space: %w", err)
}
return spc.Do(d.deviceObjectId, func(sb smartblock.SmartBlock) error {
st := sb.NewState()
st.AddDevice(device)
return sb.Apply(st)
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor SaveDeviceInfo to reduce duplication and improve error handling.

The error handling and space retrieval logic is duplicated in SaveDeviceInfo and UpdateName. Consider extracting these into a helper function to reduce code duplication and improve maintainability.

Comment on lines +50 to +60
func (d *devices) Init(a *app.App) (err error) {
d.spaceService = app.MustComponent[space.Service](a)
d.wallet = a.MustComponent(wallet.CName).(wallet.Wallet)
datastoreService := app.MustComponent[datastore.Datastore](a)
db, err := datastoreService.LocalStorage()
if err != nil {
return fmt.Errorf("failed to initialize notification store %w", err)
}
d.store = NewStore(db)
return nil
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve error handling in Init method.

The error message in line 56 could be more descriptive. It currently mentions "notification store" which might be confusing as this is related to device management.

- return fmt.Errorf("failed to initialize notification store %w", err)
+ return fmt.Errorf("failed to initialize device store: %w", err)
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (d *devices) Init(a *app.App) (err error) {
d.spaceService = app.MustComponent[space.Service](a)
d.wallet = a.MustComponent(wallet.CName).(wallet.Wallet)
datastoreService := app.MustComponent[datastore.Datastore](a)
db, err := datastoreService.LocalStorage()
if err != nil {
return fmt.Errorf("failed to initialize notification store %w", err)
}
d.store = NewStore(db)
return nil
}
func (d *devices) Init(a *app.App) (err error) {
d.spaceService = app.MustComponent[space.Service](a)
d.wallet = a.MustComponent(wallet.CName).(wallet.Wallet)
datastoreService := app.MustComponent[datastore.Datastore](a)
db, err := datastoreService.LocalStorage()
if err != nil {
return fmt.Errorf("failed to initialize device store: %w", err)
}
d.store = NewStore(db)
return nil
}

Comment on lines +167 to +181
func (d *devices) UpdateName(ctx context.Context, id, name string) error {
err := d.store.UpdateDeviceName(id, name)
if err != nil {
return fmt.Errorf("failed to update device name: %w", err)
}
spc, err := d.spaceService.Get(ctx, d.spaceService.TechSpaceId())
if err != nil {
return fmt.Errorf("failed to get space: %w", err)
}
return spc.Do(d.deviceObjectId, func(sb smartblock.SmartBlock) error {
st := sb.NewState()
st.SetDeviceName(id, name)
return sb.Apply(st)
})
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure consistent error handling in UpdateName.

The error handling in UpdateName should be consistent with other methods. Consider using the same error message format and handling strategy.

- return fmt.Errorf("failed to update device name: %w", err)
+ return fmt.Errorf("failed to update device name due to: %w", err)
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (d *devices) UpdateName(ctx context.Context, id, name string) error {
err := d.store.UpdateDeviceName(id, name)
if err != nil {
return fmt.Errorf("failed to update device name: %w", err)
}
spc, err := d.spaceService.Get(ctx, d.spaceService.TechSpaceId())
if err != nil {
return fmt.Errorf("failed to get space: %w", err)
}
return spc.Do(d.deviceObjectId, func(sb smartblock.SmartBlock) error {
st := sb.NewState()
st.SetDeviceName(id, name)
return sb.Apply(st)
})
}
func (d *devices) UpdateName(ctx context.Context, id, name string) error {
err := d.store.UpdateDeviceName(id, name)
if err != nil {
return fmt.Errorf("failed to update device name due to: %w", err)
}
spc, err := d.spaceService.Get(ctx, d.spaceService.TechSpaceId())
if err != nil {
return fmt.Errorf("failed to get space: %w", err)
}
return spc.Do(d.deviceObjectId, func(sb smartblock.SmartBlock) error {
st := sb.NewState()
st.SetDeviceName(id, name)
return sb.Apply(st)
})
}

…o-2930-store-device-names

# Conflicts:
#	clientlibrary/service/service.pb.go
#	pkg/lib/pb/model/models.pb.go
Signed-off-by: AnastasiaShemyakinskaya <shem98a@mail.ru>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 400d64d and 43a821f.

Files ignored due to path filters (2)
  • docs/proto.md is excluded by !**/proto.md
  • pkg/lib/pb/model/models.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
Files selected for processing (3)
  • core/anytype/bootstrap.go (2 hunks)
  • core/block/editor/smartblock/smartblock.go (2 hunks)
  • pkg/lib/pb/model/protos/models.proto (5 hunks)
Files skipped from review as they are similar to previous changes (3)
  • core/anytype/bootstrap.go
  • core/block/editor/smartblock/smartblock.go
  • pkg/lib/pb/model/protos/models.proto

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 43a821f and 937f3bd.

Files ignored due to path filters (4)
  • clientlibrary/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • docs/proto.md is excluded by !**/proto.md
  • pb/commands.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
  • pb/service/service.pb.go is excluded by !**/*.pb.go, !**/*.pb.go
Files selected for processing (4)
  • core/anytype/bootstrap.go (2 hunks)
  • core/block/editor/smartblock/smartblock.go (2 hunks)
  • pb/protos/commands.proto (1 hunks)
  • pb/protos/service/service.proto (1 hunks)
Files skipped from review as they are similar to previous changes (4)
  • core/anytype/bootstrap.go
  • core/block/editor/smartblock/smartblock.go
  • pb/protos/commands.proto
  • pb/protos/service/service.proto

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants