Skip to content

Commit 1cf0477

Browse files
boojackclaude
andcommitted
refactor: migrate binary file serving from gRPC to dedicated HTTP fileserver
Migrates attachment and avatar binary serving from gRPC endpoints to a new dedicated HTTP fileserver package, fixing Safari video playback issues and improving architectural separation. Key changes: - Created server/router/fileserver package for all binary file serving - Removed GetAttachmentBinary and GetUserAvatar gRPC endpoints from proto - Implemented native HTTP handlers with full range request support - Added authentication support (session cookies + JWT) to fileserver - New avatar endpoint supports lookup by user ID or username - Eliminated duplicate auth constants (imports from api/v1) HTTP endpoints: - Attachments: /file/attachments/:uid/:filename (unchanged URL) - Avatars: /file/users/:identifier/avatar (new URL format) This fixes Safari video/audio playback by using http.ServeContent() which properly handles HTTP 206 Partial Content responses and range request headers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 9ea27ee commit 1cf0477

18 files changed

+1170
-1757
lines changed

proto/api/v1/attachment_service.proto

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package memos.api.v1;
55
import "google/api/annotations.proto";
66
import "google/api/client.proto";
77
import "google/api/field_behavior.proto";
8-
import "google/api/httpbody.proto";
98
import "google/api/resource.proto";
109
import "google/protobuf/empty.proto";
1110
import "google/protobuf/field_mask.proto";
@@ -31,11 +30,6 @@ service AttachmentService {
3130
option (google.api.http) = {get: "/api/v1/{name=attachments/*}"};
3231
option (google.api.method_signature) = "name";
3332
}
34-
// GetAttachmentBinary returns a attachment binary by name.
35-
rpc GetAttachmentBinary(GetAttachmentBinaryRequest) returns (google.api.HttpBody) {
36-
option (google.api.http) = {get: "/file/{name=attachments/*}/{filename}"};
37-
option (google.api.method_signature) = "name,filename,thumbnail";
38-
}
3933
// UpdateAttachment updates a attachment.
4034
rpc UpdateAttachment(UpdateAttachmentRequest) returns (Attachment) {
4135
option (google.api.http) = {
@@ -138,21 +132,6 @@ message GetAttachmentRequest {
138132
];
139133
}
140134

141-
message GetAttachmentBinaryRequest {
142-
// Required. The attachment name of the attachment.
143-
// Format: attachments/{attachment}
144-
string name = 1 [
145-
(google.api.field_behavior) = REQUIRED,
146-
(google.api.resource_reference) = {type: "memos.api.v1/Attachment"}
147-
];
148-
149-
// The filename of the attachment. Mainly used for downloading.
150-
string filename = 2 [(google.api.field_behavior) = REQUIRED];
151-
152-
// Optional. A flag indicating if the thumbnail version of the attachment should be returned.
153-
bool thumbnail = 3 [(google.api.field_behavior) = OPTIONAL];
154-
}
155-
156135
message UpdateAttachmentRequest {
157136
// Required. The attachment which replaces the attachment on the server.
158137
Attachment attachment = 1 [(google.api.field_behavior) = REQUIRED];

proto/api/v1/user_service.proto

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import "api/v1/common.proto";
66
import "google/api/annotations.proto";
77
import "google/api/client.proto";
88
import "google/api/field_behavior.proto";
9-
import "google/api/httpbody.proto";
109
import "google/api/resource.proto";
1110
import "google/protobuf/empty.proto";
1211
import "google/protobuf/field_mask.proto";
@@ -53,12 +52,6 @@ service UserService {
5352
option (google.api.method_signature) = "name";
5453
}
5554

56-
// GetUserAvatar gets the avatar of a user.
57-
rpc GetUserAvatar(GetUserAvatarRequest) returns (google.api.HttpBody) {
58-
option (google.api.http) = {get: "/api/v1/{name=users/*}/avatar"};
59-
option (google.api.method_signature) = "name";
60-
}
61-
6255
// ListAllUserStats returns statistics for all users.
6356
rpc ListAllUserStats(ListAllUserStatsRequest) returns (ListAllUserStatsResponse) {
6457
option (google.api.http) = {get: "/api/v1/users:stats"};
@@ -324,15 +317,6 @@ message DeleteUserRequest {
324317
bool force = 2 [(google.api.field_behavior) = OPTIONAL];
325318
}
326319

327-
message GetUserAvatarRequest {
328-
// Required. The resource name of the user.
329-
// Format: users/{user}
330-
string name = 1 [
331-
(google.api.field_behavior) = REQUIRED,
332-
(google.api.resource_reference) = {type: "memos.api.v1/User"}
333-
];
334-
}
335-
336320
// User statistics messages
337321
message UserStats {
338322
option (google.api.resource) = {

proto/gen/api/v1/attachment_service.pb.go

Lines changed: 33 additions & 108 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)