#graphql #peer #p2p #peer-connection #quic #applications #syntax

discret

一个用于创建基于GraphQL语法的点对点(P2P)应用的库

3个版本

0.6.2 2024年8月6日
0.6.1 2024年8月5日
0.6.0 2024年7月31日

#1441 in 网络编程

Download history 89/week @ 2024-07-26 240/week @ 2024-08-02 19/week @ 2024-08-09

每月348次下载

自定义许可协议

1MB
29K SLoC

Discret:使用受GraphQL启发的API创建本地优先的点对点应用(P2P)

Discret隐藏了点对点网络的复杂性,将其简化为数据访问问题。

该API允许您

  • 使用GraphQL语法管理您的数据
  • 为您的数据添加访问权限(在GraphQL中也是如此)
  • 创建和接受其他节点的邀请

Discret将根据您授予其他节点的访问权限同步您的数据

更多详细信息和使用教程可在文档网站中找到

示例

以下示例创建了一个非常基本的聊天应用。如果您在不同的文件夹或本地网络设备上构建并运行此程序,您应该能够与自己聊天。

use std::{io, path::PathBuf};
use discret::{
    derive_pass_phrase, zero_uid, Configuration, Discret,
    Parameters, ParametersAdd, ResultParser,
};
use serde::Deserialize;
//the application unique identifier
const APPLICATION_KEY: &str = "github.com/discretlib/rust_example_simple_chat";
#[tokio::main]
async fn main() {
    //define a datamodel
    let model = "chat {
        Message{
            content:String
        }
    }";
    //this struct is used to parse the query result
    #[derive(Deserialize)]
    struct Chat {
        pub id: String,
        pub mdate: i64,
        pub content: String,
    }
    let path: PathBuf = "test_data".into(); //where data is stored
    //used to derives all necessary secrets
    let key_material: [u8; 32] = derive_pass_phrase("my login", "my password");
    //start the discret application
    let app: Discret = Discret::new(
        model,
        APPLICATION_KEY,
        &key_material,
        path,
        Configuration::default(),
    )
    .await
    .unwrap();
    //listen for events
    let mut events = app.subscribe_for_events().await;
    let event_app: Discret = app.clone();
    tokio::spawn(async move {
        let mut last_date = 0;
        let mut last_id = zero_uid();
        let private_room: String = event_app.private_room();
        while let Ok(event) = events.recv().await {
            match event {
                //triggered when data is modified
                discret::Event::DataChanged(_) => {
                    let mut param = Parameters::new();
                    param.add("mdate", last_date).unwrap();
                    param.add("id", last_id.clone()).unwrap();
                    param.add("room_id", private_room.clone()).unwrap();
                    //get the latest data, the result is in the JSON format
                    let result: String = event_app
                        .query(
                            "query {
                                res: chat.Message(
                                    order_by(mdate asc, id asc),
                                    after($mdate, $id),
                                    room_id = $room_id
                                ) {
                                        id
                                        mdate
                                        content
                                }
                            }",
                            Some(param),
                        )
                        .await
                        .unwrap();
                    let mut query_result = ResultParser::new(&result).unwrap();
                    let res: Vec<Chat> = query_result.take_array("res").unwrap();
                    for msg in res {
                        last_date = msg.mdate;
                        last_id = msg.id;
                        println!("you said: {}", msg.content);
                    }
                }
                _ => {} //ignores other events
            }
        }
    });
    //data is inserted in your private room
    let private_room: String = app.private_room();
    let stdin = io::stdin();
    let mut line = String::new();
    println!("{}", "Write Something!");
    loop {
        stdin.read_line(&mut line).unwrap();
        if line.starts_with("/q") {
            break;
        }
        line.pop();
        let mut params = Parameters::new();
        params.add("message", line.clone()).unwrap();
        params.add("room_id", private_room.clone()).unwrap();
        app.mutate(
            "mutate {
                chat.Message {
                    room_id:$room_id
                    content: $message
                }
            }",
            Some(params),
        )
        .await
        .unwrap();
        line.clear();
    }
}

功能

Discret提供了一个阻塞(DiscretBlocking)和一个非阻塞(Discret)API。

在本地网络中,节点连接不需要服务器。对于互联网上的点对点连接,需要一个发现服务器以允许节点相互发现。Discret库提供了一个名为Beacon的发现服务器的实现。

该库提供了一组强大的安全功能

  • 数据在SQLCipher数据库中加密存储
  • 使用QUIC协议进行加密通信
  • 数据完整性:每一行都使用节点签名密钥进行签名,使其难以同步不良数据
  • 通过房间进行访问控制

限制

由于数据存储在您的设备上,Discret仅适用于生成“真实人类”数据的、最多有数百个节点的应用程序。它不适合大规模应用程序和拥有数千人的社区。

它目前仅支持文本数据,但计划支持文件同步。

互联网连接不保证100%正常工作,因为某些类型的商业防火墙将阻止连接尝试。

请小心,P2P连接会泄露您的IP地址,并且只能与受信任的节点一起使用。这种泄露使您面临以下威胁

  • 分布式拒绝服务(DDoS)
  • 通过地理位置服务泄露您的“现实世界”位置。
  • 国家支持的监视:监视网络的机构可以确定哪些节点连接到哪些节点,从而获得大量关于您社交网络的知识。

平台支持

  • Linux:已测试
  • Windows: 已测试
  • macOS: 未测试,应能工作
  • Android: 在 arch64 架构上工作。i686 和 x86_64 架构与 Flutter 一起使用时存在一些低级链接器问题。
  • iOS: 未测试

依赖项

~44–77MB
~1.5M SLoC