Make project id optional when following - server only
This commit is contained in:
parent
83455028b0
commit
c71566e7f5
10 changed files with 204 additions and 55 deletions
|
@ -175,7 +175,7 @@ CREATE TABLE "servers" (
|
||||||
CREATE TABLE "followers" (
|
CREATE TABLE "followers" (
|
||||||
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
"id" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
"room_id" INTEGER NOT NULL REFERENCES rooms (id) ON DELETE CASCADE,
|
"room_id" INTEGER NOT NULL REFERENCES rooms (id) ON DELETE CASCADE,
|
||||||
"project_id" INTEGER NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
|
"project_id" INTEGER REFERENCES projects (id) ON DELETE CASCADE,
|
||||||
"leader_connection_server_id" INTEGER NOT NULL REFERENCES servers (id) ON DELETE CASCADE,
|
"leader_connection_server_id" INTEGER NOT NULL REFERENCES servers (id) ON DELETE CASCADE,
|
||||||
"leader_connection_id" INTEGER NOT NULL,
|
"leader_connection_id" INTEGER NOT NULL,
|
||||||
"follower_connection_server_id" INTEGER NOT NULL REFERENCES servers (id) ON DELETE CASCADE,
|
"follower_connection_server_id" INTEGER NOT NULL REFERENCES servers (id) ON DELETE CASCADE,
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE followers ALTER COLUMN project_id DROP NOT NULL;
|
|
@ -738,7 +738,7 @@ impl Database {
|
||||||
Condition::any()
|
Condition::any()
|
||||||
.add(
|
.add(
|
||||||
Condition::all()
|
Condition::all()
|
||||||
.add(follower::Column::ProjectId.eq(project_id))
|
.add(follower::Column::ProjectId.eq(Some(project_id)))
|
||||||
.add(
|
.add(
|
||||||
follower::Column::LeaderConnectionServerId
|
follower::Column::LeaderConnectionServerId
|
||||||
.eq(connection.owner_id),
|
.eq(connection.owner_id),
|
||||||
|
@ -747,7 +747,7 @@ impl Database {
|
||||||
)
|
)
|
||||||
.add(
|
.add(
|
||||||
Condition::all()
|
Condition::all()
|
||||||
.add(follower::Column::ProjectId.eq(project_id))
|
.add(follower::Column::ProjectId.eq(Some(project_id)))
|
||||||
.add(
|
.add(
|
||||||
follower::Column::FollowerConnectionServerId
|
follower::Column::FollowerConnectionServerId
|
||||||
.eq(connection.owner_id),
|
.eq(connection.owner_id),
|
||||||
|
@ -862,13 +862,95 @@ impl Database {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn check_can_follow(
|
||||||
|
&self,
|
||||||
|
room_id: RoomId,
|
||||||
|
project_id: Option<ProjectId>,
|
||||||
|
leader_id: ConnectionId,
|
||||||
|
follower_id: ConnectionId,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut found_leader = false;
|
||||||
|
let mut found_follower = false;
|
||||||
|
self.transaction(|tx| async move {
|
||||||
|
if let Some(project_id) = project_id {
|
||||||
|
let mut rows = project_collaborator::Entity::find()
|
||||||
|
.filter(project_collaborator::Column::ProjectId.eq(project_id))
|
||||||
|
.stream(&*tx)
|
||||||
|
.await?;
|
||||||
|
while let Some(row) = rows.next().await {
|
||||||
|
let row = row?;
|
||||||
|
let connection = row.connection();
|
||||||
|
if connection == leader_id {
|
||||||
|
found_leader = true;
|
||||||
|
} else if connection == follower_id {
|
||||||
|
found_follower = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut rows = room_participant::Entity::find()
|
||||||
|
.filter(room_participant::Column::RoomId.eq(room_id))
|
||||||
|
.stream(&*tx)
|
||||||
|
.await?;
|
||||||
|
while let Some(row) = rows.next().await {
|
||||||
|
let row = row?;
|
||||||
|
if let Some(connection) = row.answering_connection() {
|
||||||
|
if connection == leader_id {
|
||||||
|
found_leader = true;
|
||||||
|
} else if connection == follower_id {
|
||||||
|
found_follower = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found_leader || !found_follower {
|
||||||
|
Err(anyhow!("not a room participant"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn check_can_unfollow(
|
||||||
|
&self,
|
||||||
|
room_id: RoomId,
|
||||||
|
project_id: Option<ProjectId>,
|
||||||
|
leader_id: ConnectionId,
|
||||||
|
follower_id: ConnectionId,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.transaction(|tx| async move {
|
||||||
|
follower::Entity::find()
|
||||||
|
.filter(
|
||||||
|
Condition::all()
|
||||||
|
.add(follower::Column::RoomId.eq(room_id))
|
||||||
|
.add(follower::Column::ProjectId.eq(project_id))
|
||||||
|
.add(follower::Column::LeaderConnectionId.eq(leader_id.id as i32))
|
||||||
|
.add(follower::Column::FollowerConnectionId.eq(follower_id.id as i32))
|
||||||
|
.add(
|
||||||
|
follower::Column::LeaderConnectionServerId
|
||||||
|
.eq(leader_id.owner_id as i32),
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
follower::Column::FollowerConnectionServerId
|
||||||
|
.eq(follower_id.owner_id as i32),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.one(&*tx)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| anyhow!("not a follower"))?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn follow(
|
pub async fn follow(
|
||||||
&self,
|
&self,
|
||||||
project_id: ProjectId,
|
room_id: RoomId,
|
||||||
|
project_id: Option<ProjectId>,
|
||||||
leader_connection: ConnectionId,
|
leader_connection: ConnectionId,
|
||||||
follower_connection: ConnectionId,
|
follower_connection: ConnectionId,
|
||||||
) -> Result<RoomGuard<proto::Room>> {
|
) -> Result<RoomGuard<proto::Room>> {
|
||||||
let room_id = self.room_id_for_project(project_id).await?;
|
|
||||||
self.room_transaction(room_id, |tx| async move {
|
self.room_transaction(room_id, |tx| async move {
|
||||||
follower::ActiveModel {
|
follower::ActiveModel {
|
||||||
room_id: ActiveValue::set(room_id),
|
room_id: ActiveValue::set(room_id),
|
||||||
|
@ -894,15 +976,16 @@ impl Database {
|
||||||
|
|
||||||
pub async fn unfollow(
|
pub async fn unfollow(
|
||||||
&self,
|
&self,
|
||||||
project_id: ProjectId,
|
room_id: RoomId,
|
||||||
|
project_id: Option<ProjectId>,
|
||||||
leader_connection: ConnectionId,
|
leader_connection: ConnectionId,
|
||||||
follower_connection: ConnectionId,
|
follower_connection: ConnectionId,
|
||||||
) -> Result<RoomGuard<proto::Room>> {
|
) -> Result<RoomGuard<proto::Room>> {
|
||||||
let room_id = self.room_id_for_project(project_id).await?;
|
|
||||||
self.room_transaction(room_id, |tx| async move {
|
self.room_transaction(room_id, |tx| async move {
|
||||||
follower::Entity::delete_many()
|
follower::Entity::delete_many()
|
||||||
.filter(
|
.filter(
|
||||||
Condition::all()
|
Condition::all()
|
||||||
|
.add(follower::Column::RoomId.eq(room_id))
|
||||||
.add(follower::Column::ProjectId.eq(project_id))
|
.add(follower::Column::ProjectId.eq(project_id))
|
||||||
.add(
|
.add(
|
||||||
follower::Column::LeaderConnectionServerId
|
follower::Column::LeaderConnectionServerId
|
||||||
|
|
|
@ -960,6 +960,65 @@ impl Database {
|
||||||
Ok(room)
|
Ok(room)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn room_id_for_connection(&self, connection_id: ConnectionId) -> Result<RoomId> {
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
|
||||||
|
enum QueryRoomId {
|
||||||
|
RoomId,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.transaction(|tx| async move {
|
||||||
|
Ok(room_participant::Entity::find()
|
||||||
|
.select_only()
|
||||||
|
.column(room_participant::Column::RoomId)
|
||||||
|
.filter(
|
||||||
|
Condition::all()
|
||||||
|
.add(room_participant::Column::AnsweringConnectionId.eq(connection_id.id))
|
||||||
|
.add(
|
||||||
|
room_participant::Column::AnsweringConnectionServerId
|
||||||
|
.eq(ServerId(connection_id.owner_id as i32)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.into_values::<_, QueryRoomId>()
|
||||||
|
.one(&*tx)
|
||||||
|
.await?
|
||||||
|
.ok_or_else(|| anyhow!("no room for connection {:?}", connection_id))?)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn room_connection_ids(
|
||||||
|
&self,
|
||||||
|
room_id: RoomId,
|
||||||
|
connection_id: ConnectionId,
|
||||||
|
) -> Result<RoomGuard<HashSet<ConnectionId>>> {
|
||||||
|
self.room_transaction(room_id, |tx| async move {
|
||||||
|
let mut participants = room_participant::Entity::find()
|
||||||
|
.filter(room_participant::Column::RoomId.eq(room_id))
|
||||||
|
.stream(&*tx)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let mut is_participant = false;
|
||||||
|
let mut connection_ids = HashSet::default();
|
||||||
|
while let Some(participant) = participants.next().await {
|
||||||
|
let participant = participant?;
|
||||||
|
if let Some(answering_connection) = participant.answering_connection() {
|
||||||
|
if answering_connection == connection_id {
|
||||||
|
is_participant = true;
|
||||||
|
} else {
|
||||||
|
connection_ids.insert(answering_connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !is_participant {
|
||||||
|
Err(anyhow!("not a room participant"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(connection_ids)
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_channel_room(
|
async fn get_channel_room(
|
||||||
&self,
|
&self,
|
||||||
room_id: RoomId,
|
room_id: RoomId,
|
||||||
|
@ -1064,7 +1123,7 @@ impl Database {
|
||||||
followers.push(proto::Follower {
|
followers.push(proto::Follower {
|
||||||
leader_id: Some(db_follower.leader_connection().into()),
|
leader_id: Some(db_follower.leader_connection().into()),
|
||||||
follower_id: Some(db_follower.follower_connection().into()),
|
follower_id: Some(db_follower.follower_connection().into()),
|
||||||
project_id: db_follower.project_id.to_proto(),
|
project_id: db_follower.project_id.map(|id| id.to_proto()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ pub struct Model {
|
||||||
#[sea_orm(primary_key)]
|
#[sea_orm(primary_key)]
|
||||||
pub id: FollowerId,
|
pub id: FollowerId,
|
||||||
pub room_id: RoomId,
|
pub room_id: RoomId,
|
||||||
pub project_id: ProjectId,
|
pub project_id: Option<ProjectId>,
|
||||||
pub leader_connection_server_id: ServerId,
|
pub leader_connection_server_id: ServerId,
|
||||||
pub leader_connection_id: i32,
|
pub leader_connection_id: i32,
|
||||||
pub follower_connection_server_id: ServerId,
|
pub follower_connection_server_id: ServerId,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::db::{ProjectId, RoomId, RoomParticipantId, ServerId, UserId};
|
use crate::db::{ProjectId, RoomId, RoomParticipantId, ServerId, UserId};
|
||||||
|
use rpc::ConnectionId;
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
|
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
|
||||||
|
@ -19,6 +20,15 @@ pub struct Model {
|
||||||
pub calling_connection_server_id: Option<ServerId>,
|
pub calling_connection_server_id: Option<ServerId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Model {
|
||||||
|
pub fn answering_connection(&self) -> Option<ConnectionId> {
|
||||||
|
Some(ConnectionId {
|
||||||
|
owner_id: self.answering_connection_server_id?.0 as u32,
|
||||||
|
id: self.answering_connection_id? as u32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
pub enum Relation {
|
pub enum Relation {
|
||||||
#[sea_orm(
|
#[sea_orm(
|
||||||
|
|
|
@ -1883,24 +1883,19 @@ async fn follow(
|
||||||
response: Response<proto::Follow>,
|
response: Response<proto::Follow>,
|
||||||
session: Session,
|
session: Session,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let project_id = ProjectId::from_proto(request.project_id);
|
let room_id = RoomId::from_proto(request.room_id);
|
||||||
|
let project_id = request.project_id.map(ProjectId::from_proto);
|
||||||
let leader_id = request
|
let leader_id = request
|
||||||
.leader_id
|
.leader_id
|
||||||
.ok_or_else(|| anyhow!("invalid leader id"))?
|
.ok_or_else(|| anyhow!("invalid leader id"))?
|
||||||
.into();
|
.into();
|
||||||
let follower_id = session.connection_id;
|
let follower_id = session.connection_id;
|
||||||
|
|
||||||
{
|
session
|
||||||
let project_connection_ids = session
|
.db()
|
||||||
.db()
|
.await
|
||||||
.await
|
.check_can_follow(room_id, project_id, leader_id, session.connection_id)
|
||||||
.project_connection_ids(project_id, session.connection_id)
|
.await?;
|
||||||
.await?;
|
|
||||||
|
|
||||||
if !project_connection_ids.contains(&leader_id) {
|
|
||||||
Err(anyhow!("no such peer"))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut response_payload = session
|
let mut response_payload = session
|
||||||
.peer
|
.peer
|
||||||
|
@ -1914,7 +1909,7 @@ async fn follow(
|
||||||
let room = session
|
let room = session
|
||||||
.db()
|
.db()
|
||||||
.await
|
.await
|
||||||
.follow(project_id, leader_id, follower_id)
|
.follow(room_id, project_id, leader_id, follower_id)
|
||||||
.await?;
|
.await?;
|
||||||
room_updated(&room, &session.peer);
|
room_updated(&room, &session.peer);
|
||||||
|
|
||||||
|
@ -1922,22 +1917,19 @@ async fn follow(
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn unfollow(request: proto::Unfollow, session: Session) -> Result<()> {
|
async fn unfollow(request: proto::Unfollow, session: Session) -> Result<()> {
|
||||||
let project_id = ProjectId::from_proto(request.project_id);
|
let room_id = RoomId::from_proto(request.room_id);
|
||||||
|
let project_id = request.project_id.map(ProjectId::from_proto);
|
||||||
let leader_id = request
|
let leader_id = request
|
||||||
.leader_id
|
.leader_id
|
||||||
.ok_or_else(|| anyhow!("invalid leader id"))?
|
.ok_or_else(|| anyhow!("invalid leader id"))?
|
||||||
.into();
|
.into();
|
||||||
let follower_id = session.connection_id;
|
let follower_id = session.connection_id;
|
||||||
|
|
||||||
if !session
|
session
|
||||||
.db()
|
.db()
|
||||||
.await
|
.await
|
||||||
.project_connection_ids(project_id, session.connection_id)
|
.check_can_unfollow(room_id, project_id, leader_id, session.connection_id)
|
||||||
.await?
|
.await?;
|
||||||
.contains(&leader_id)
|
|
||||||
{
|
|
||||||
Err(anyhow!("no such peer"))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
session
|
session
|
||||||
.peer
|
.peer
|
||||||
|
@ -1946,7 +1938,7 @@ async fn unfollow(request: proto::Unfollow, session: Session) -> Result<()> {
|
||||||
let room = session
|
let room = session
|
||||||
.db()
|
.db()
|
||||||
.await
|
.await
|
||||||
.unfollow(project_id, leader_id, follower_id)
|
.unfollow(room_id, project_id, leader_id, follower_id)
|
||||||
.await?;
|
.await?;
|
||||||
room_updated(&room, &session.peer);
|
room_updated(&room, &session.peer);
|
||||||
|
|
||||||
|
@ -1954,13 +1946,19 @@ async fn unfollow(request: proto::Unfollow, session: Session) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_followers(request: proto::UpdateFollowers, session: Session) -> Result<()> {
|
async fn update_followers(request: proto::UpdateFollowers, session: Session) -> Result<()> {
|
||||||
let project_id = ProjectId::from_proto(request.project_id);
|
let room_id = RoomId::from_proto(request.room_id);
|
||||||
let project_connection_ids = session
|
let database = session.db.lock().await;
|
||||||
.db
|
|
||||||
.lock()
|
let connection_ids = if let Some(project_id) = request.project_id {
|
||||||
.await
|
let project_id = ProjectId::from_proto(project_id);
|
||||||
.project_connection_ids(project_id, session.connection_id)
|
database
|
||||||
.await?;
|
.project_connection_ids(project_id, session.connection_id)
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
database
|
||||||
|
.room_connection_ids(room_id, session.connection_id)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
let leader_id = request.variant.as_ref().and_then(|variant| match variant {
|
let leader_id = request.variant.as_ref().and_then(|variant| match variant {
|
||||||
proto::update_followers::Variant::CreateView(payload) => payload.leader_id,
|
proto::update_followers::Variant::CreateView(payload) => payload.leader_id,
|
||||||
|
@ -1969,9 +1967,7 @@ async fn update_followers(request: proto::UpdateFollowers, session: Session) ->
|
||||||
});
|
});
|
||||||
for follower_peer_id in request.follower_ids.iter().copied() {
|
for follower_peer_id in request.follower_ids.iter().copied() {
|
||||||
let follower_connection_id = follower_peer_id.into();
|
let follower_connection_id = follower_peer_id.into();
|
||||||
if project_connection_ids.contains(&follower_connection_id)
|
if Some(follower_peer_id) != leader_id && connection_ids.contains(&follower_connection_id) {
|
||||||
&& Some(follower_peer_id) != leader_id
|
|
||||||
{
|
|
||||||
session.peer.forward_send(
|
session.peer.forward_send(
|
||||||
session.connection_id,
|
session.connection_id,
|
||||||
follower_connection_id,
|
follower_connection_id,
|
||||||
|
|
|
@ -274,7 +274,7 @@ message ParticipantProject {
|
||||||
message Follower {
|
message Follower {
|
||||||
PeerId leader_id = 1;
|
PeerId leader_id = 1;
|
||||||
PeerId follower_id = 2;
|
PeerId follower_id = 2;
|
||||||
uint64 project_id = 3;
|
optional uint64 project_id = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ParticipantLocation {
|
message ParticipantLocation {
|
||||||
|
@ -1213,8 +1213,9 @@ message UpdateDiagnostics {
|
||||||
}
|
}
|
||||||
|
|
||||||
message Follow {
|
message Follow {
|
||||||
uint64 project_id = 1;
|
uint64 room_id = 1;
|
||||||
PeerId leader_id = 2;
|
optional uint64 project_id = 2;
|
||||||
|
PeerId leader_id = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message FollowResponse {
|
message FollowResponse {
|
||||||
|
@ -1223,18 +1224,20 @@ message FollowResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateFollowers {
|
message UpdateFollowers {
|
||||||
uint64 project_id = 1;
|
uint64 room_id = 1;
|
||||||
repeated PeerId follower_ids = 2;
|
optional uint64 project_id = 2;
|
||||||
|
repeated PeerId follower_ids = 3;
|
||||||
oneof variant {
|
oneof variant {
|
||||||
UpdateActiveView update_active_view = 3;
|
UpdateActiveView update_active_view = 4;
|
||||||
View create_view = 4;
|
View create_view = 5;
|
||||||
UpdateView update_view = 5;
|
UpdateView update_view = 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message Unfollow {
|
message Unfollow {
|
||||||
uint64 project_id = 1;
|
uint64 room_id = 1;
|
||||||
PeerId leader_id = 2;
|
optional uint64 project_id = 2;
|
||||||
|
PeerId leader_id = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetPrivateUserInfo {}
|
message GetPrivateUserInfo {}
|
||||||
|
|
|
@ -364,7 +364,6 @@ entity_messages!(
|
||||||
CreateProjectEntry,
|
CreateProjectEntry,
|
||||||
DeleteProjectEntry,
|
DeleteProjectEntry,
|
||||||
ExpandProjectEntry,
|
ExpandProjectEntry,
|
||||||
Follow,
|
|
||||||
FormatBuffers,
|
FormatBuffers,
|
||||||
GetCodeActions,
|
GetCodeActions,
|
||||||
GetCompletions,
|
GetCompletions,
|
||||||
|
@ -392,12 +391,10 @@ entity_messages!(
|
||||||
SearchProject,
|
SearchProject,
|
||||||
StartLanguageServer,
|
StartLanguageServer,
|
||||||
SynchronizeBuffers,
|
SynchronizeBuffers,
|
||||||
Unfollow,
|
|
||||||
UnshareProject,
|
UnshareProject,
|
||||||
UpdateBuffer,
|
UpdateBuffer,
|
||||||
UpdateBufferFile,
|
UpdateBufferFile,
|
||||||
UpdateDiagnosticSummary,
|
UpdateDiagnosticSummary,
|
||||||
UpdateFollowers,
|
|
||||||
UpdateLanguageServer,
|
UpdateLanguageServer,
|
||||||
UpdateProject,
|
UpdateProject,
|
||||||
UpdateProjectCollaborator,
|
UpdateProjectCollaborator,
|
||||||
|
|
|
@ -6,4 +6,4 @@ pub use conn::Connection;
|
||||||
pub use peer::*;
|
pub use peer::*;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub const PROTOCOL_VERSION: u32 = 63;
|
pub const PROTOCOL_VERSION: u32 = 64;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue