First commit of codemp-proto in new repo

This commit is contained in:
frelodev 2024-03-09 18:45:32 +01:00
commit 5ecd52d237
10 changed files with 249 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
Cargo.lock

15
Cargo.toml Normal file
View file

@ -0,0 +1,15 @@
[package]
name = "codemp-proto"
version = "0.6.0"
edition = "2021"
[lib]
name = "codemp_proto"
[dependencies]
prost = "0.12.3"
tonic = "0.11.0"
uuid = "1.7.0"
[build-dependencies]
tonic-build = "0.11.0"

15
build.rs Normal file
View file

@ -0,0 +1,15 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure()
.compile(
&[
"proto/common.proto",
"proto/cursor.proto",
"proto/files.proto",
"proto/auth.proto",
"proto/workspace.proto",
"proto/buffer.proto",
],
&["proto"],
)?;
Ok(())
}

20
proto/auth.proto Normal file
View file

@ -0,0 +1,20 @@
syntax = "proto2";
package auth;
// authenticates users, issuing tokens
service Auth {
// send credentials and join a workspace, returns ready to use token
rpc Login (WorkspaceJoinRequest) returns (Token);
}
message Token {
required string token = 1;
}
// TODO one-request-to-do-it-all from login to workspace access
message WorkspaceJoinRequest {
required string username = 1;
required string password = 2;
optional string workspace_id = 3;
}

20
proto/buffer.proto Normal file
View file

@ -0,0 +1,20 @@
syntax = "proto2";
import "common.proto";
package buffer;
// handle buffer changes, keep in sync users
service Buffer {
// attach to a buffer and receive operations
rpc Attach (stream Operation) returns (stream BufferEvent);
}
message Operation {
required bytes data = 1;
}
message BufferEvent {
required Operation op = 1;
required common.Identity user = 2;
}

18
proto/common.proto Normal file
View file

@ -0,0 +1,18 @@
syntax = "proto2";
package common;
// a wrapper payload representing an uuid
message Identity {
// uuid bytes, as string
required string id = 1;
}
// a collection of identities
message IdentityList {
repeated Identity users = 1;
}
//generic Empty message
message Empty { }

36
proto/cursor.proto Normal file
View file

@ -0,0 +1,36 @@
syntax = "proto2";
package cursor;
import "common.proto";
import "files.proto";
// handle cursor events and broadcast to all users
service Cursor {
// subscribe to a workspace's cursor events
rpc Attach (stream cursor.CursorPosition) returns (stream cursor.CursorEvent);
}
// a tuple indicating row and column
message RowCol {
required int32 row = 1;
required int32 col = 2;
}
// cursor position object
message CursorPosition {
// path of current buffer this cursor is into
required files.BufferNode buffer = 1;
// cursor start position
required RowCol start = 2;
// cursor end position
required RowCol end = 3;
}
// cursor event, with user id and cursor position
message CursorEvent {
// user moving the cursor
required common.Identity user = 1;
// new cursor position
required CursorPosition position = 2;
}

11
proto/files.proto Normal file
View file

@ -0,0 +1,11 @@
syntax = "proto2";
package files;
message BufferNode {
required string path = 1;
}
message BufferTree {
repeated BufferNode buffers = 1;
}

54
proto/workspace.proto Normal file
View file

@ -0,0 +1,54 @@
syntax = "proto2";
package workspace;
import "common.proto";
import "files.proto";
import "auth.proto";
service Workspace {
rpc Attach (common.Empty) returns (stream WorkspaceEvent);
rpc CreateBuffer (files.BufferNode) returns (common.Empty);
rpc AccessBuffer (files.BufferNode) returns (BufferCredentials);
rpc DeleteBuffer (files.BufferNode) returns (common.Empty);
rpc ListBuffers (common.Empty) returns (files.BufferTree);
rpc ListUsers (common.Empty) returns (common.IdentityList);
rpc ListBufferUsers (files.BufferNode) returns (common.IdentityList);
}
message WorkspaceEvent {
message UserJoin {
required common.Identity user = 1;
}
message UserLeave {
required common.Identity user = 1;
}
message FileCreate {
required string path = 1;
}
message FileRename {
required string before = 1;
required string after = 2;
}
message FileDelete {
required string path = 1;
}
oneof event {
UserJoin join = 1;
UserLeave leave = 2;
FileCreate create = 3;
FileRename rename = 4;
FileDelete delete = 5;
}
}
// TODO this is very ugly because we can't just return a new token (which is already smelly but whatev), we also need to tell the underlying id so that
// the client can put it as metadata while attaching, because it can't really know the underlying id that the server is using for each buffer without
// parsing the token itself. meehhhhhh, this bleeds underlying implementation to the upper levels, how can we avoid this??
message BufferCredentials {
required common.Identity id = 1;
required auth.Token token = 2;
}

58
src/lib.rs Normal file
View file

@ -0,0 +1,58 @@
#[allow(non_snake_case)]
pub mod proto {
pub mod common {
tonic::include_proto!("common");
impl From<uuid::Uuid> for Identity {
fn from(id: uuid::Uuid) -> Self {
Identity { id: id.to_string() }
}
}
impl From<&uuid::Uuid> for Identity {
fn from(id: &uuid::Uuid) -> Self {
Identity { id: id.to_string() }
}
}
impl From<Identity> for uuid::Uuid {
fn from(value: Identity) -> Self {
uuid::Uuid::parse_str(&value.id).expect("invalid uuid in identity")
}
}
impl From<&Identity> for uuid::Uuid {
fn from(value: &Identity) -> Self {
uuid::Uuid::parse_str(&value.id).expect("invalid uuid in identity")
}
}
}
pub mod files {
tonic::include_proto!("files");
impl From<String> for BufferNode {
fn from(value: String) -> Self {
BufferNode { path: value }
}
}
impl From<&str> for BufferNode {
fn from(value: &str) -> Self {
BufferNode { path: value.to_string() }
}
}
impl From<BufferNode> for String {
fn from(value: BufferNode) -> Self {
value.path
}
}
}
pub mod buffer { tonic::include_proto!("buffer"); }
pub mod cursor { tonic::include_proto!("cursor"); }
pub mod workspace { tonic::include_proto!("workspace"); }
pub mod auth { tonic::include_proto!("auth"); }
}