60个版本
0.7.0-alpha.25 | 2023年7月6日 |
---|---|
0.7.0-alpha.24 | 2022年12月19日 |
0.7.0-alpha.20 | 2022年3月31日 |
0.7.0-alpha.14 | 2021年11月19日 |
0.2.0 | 2018年5月19日 |
#48 in 视频
98 个月下载量
在 2 crate 中使用
570KB
8K SLoC
ActivityStreams
由ActivityStreams和ActivityPub规范组成的一套特质和类型
- 在 git.asonix.dog 上找到代码
- 在 docs.rs 上阅读文档
- 在 #activitystreams:asonix.dog 的matrix频道加入
- 在 mastodon 上联系我
使用方法
首先,将ActivityStreams添加到您的依赖项中
[dependencies]
activitystreams = "0.7.0-alpha.19"
类型
该项目按Kind => Type布局
因此,要使用ActivityStreams视频,您会编写
use activitystreams::object::Video;
let video = Video::new();
要使用ActivityPub配置文件,您会编写
use activitystreams::object::{ApObject, Profile};
let inner = Profile::new();
let profile = ApObject::new(inner);
只有一个类型的Link
use activitystreams::link::Mention;
let mention = Mention::new();
字段
提供的类型中的许多字段都封装在OneOrMany<>
或具有AnyBase
类型。这是因为activitystreams规范对被认为有效的结构非常开放。
例如,ActivityStreams中的Object类型有一个summary
字段,该字段可以表示为xsd:string
或rdf:langString
。它还指出,summary
字段不是functional
,这意味着可以出现任意数量的xsd:string
或rdf:langString
,或它们的组合。这个库将其表示为Option<OneOrMany<AnyString>>
。
此结果类型正好足够具体,可以匹配以下有效的ActivityStreams json,而不匹配任何无效的json。
没有摘要
{}
具有字符串摘要
{
"summary": "A string"
}
具有rdf langstring
{
"summary": {
"@value": "A string",
"@language": "en"
}
}
具有多个值
{
"summary": [
{
"@value": "A string",
"@language": "en"
},
"An xsd:string this time"
]
}
虽然与这些类型交互可能会变得繁琐,但根据其内部内容,对OneOrMany
类型实现了某些自定义方法。
fn from_xsd_string<T>(&mut self, T) -> Self;
fn from_rdf_lang_string<T>(&mut self, T) -> Self;
fn as_single_xsd_string(&self) -> Option<&str>;
fn as_single_rdf_langstring(&self) -> Option<&RdfLangString>;
fn single_xsd_string(self) -> Option<String>;
fn single_rdf_lang_string(self) -> Option<RdfLangString>;
fn add_xsd_string<T>(&mut self, T) -> &mut Self;
fn add_rdf_lang_string<T>(&mut self, T) -> &mut Self;
这些方法提供对设置和获取统一类型数据的访问,以及删除数据的功能。在设置方法中,类型参数 T 被绑定到 Into<String>
或 Into<RdfLangString>
。这允许将可以转换为这些类型的值传递给方法,而不是要求调用者执行转换。
像 RdfLangString
这样的类型可以在 primitives
模块中找到。除非你正在构建自己的自定义类型,否则通常不需要你自己导入它们。它们每个都实现了用于解析的 FromStr
和将字符串转换回的 Display
,以及用于你可能期望的类型(例如 XsdNonNegativeInteger
实现了 From<u64>
和 Into<u64>
)的 From
和 Into
或 TryFrom
和 TryInto
。
特性
由于 ActivityStreams 是一种数据层次结构,它表示为包含其他结构体的结构体。这意味着任何 ActivityStreams 类型都可能出现的 context
字段将位于最内层的结构体中。为了避免编写像 ap_object.collection.object.base.context = Some(context())
这样的代码,这个库提供了一些特性,这些特性会为提供的类型自动实现。
例如,BaseExt
特性为 context
提供以下方法,
fn context(&self) -> Option<&OneOrMany<AnyBase>>;
fn set_context<T>(&mut self, context: T) -> &mut Self
where
T: Into<AnyBase>;
fn set_many_contexts<I, T>(&mut self, items: I) -> &mut Self
where
I: IntoIterator<Item = T>,
T: Into<AnyBase>;
fn add_context<T>(&mut self, context: T) -> &mut Self
where
T: Into<AnyBase>;
fn take_context(&mut self) -> Option<OneOrMany<AnyBase>>;
fn delete_context(&mut self) -> &mut Self;
对于像 id
这样具有更具体界限的字段,
fn id(&self) -> Option<&XsdAnyUri>;
fn set_id(&mut self, XsdAnyUri) -> &mut Self;
fn take_id(&self) -> Option<XsdAnyUri>;
fn delete_id(&mut self) -> &mut Self;
实现类似方法的扩展特性的完整列表可以在预览模块中找到。通过使用 use activitystreams::prelude::*;
,所有方法都将为包含其字段的数据类型实现。
标记
这个库提供了一系列特性,如 Object
、Link
、Actor
、Activity
、Collection
和 CollectionPage
。其中大多数特性仅仅是为了“标记”类型,这意味着它们在运行时没有提供任何值,但存在于编译时添加泛型约束。
如果你想创建一个只操作 Activity 而不是普通对象的函数,你可以这样绑定函数
use activitystreams::{base::BaseExt, context, markers::Activity, iri};
fn manipulator<T, Kind>(mut activity: T) -> Result<(), anyhow::Error>
where
T: Activity + BaseExt<Kind>,
{
activity
.set_id(iri!("https://example.com"))
.set_context(context());
Ok(())
}
类型
这个库有一组单元结构体,可以将字符串序列化和反序列化。这是为了使不同的 ActivityPub 对象类型可以反序列化为不同的命名结构体。这些可以在 activitystreams::objects::kind
和类似路径中找到。
例如,要构建自己的 Person 结构体,你可以这样写
use activitystreams::actor::kind::PersonType;
#[derive(serde::Deserialize, serde::Serialize)]
pub struct MyPerson {
// Do a rename since `type` is not a valid rust field name
#[serde(rename = "type")]
kind: PersonType,
}
这种类型只会在JSON中反序列化,其中"type":"Person"
示例
创建
use activitystreams::{
context,
object::{ApObject, Video},
prelude::*,
iri,
};
fn main() -> Result<(), anyhow::Error> {
let mut video = ApObject::new(Video::new());
video
.set_context(context())
.set_id(iri!("https://example.com/@example/lions"))
.set_media_type("video/webm".parse()?)
.set_url(iri!("https://example.com/@example/lions/video.webm"))
.set_summary("A cool video")
.set_duration("PT4M20S".parse()?)
.set_shares(iri!("https://example.com/@example/lions/video.webm#shares"));
println!("Video, {:#?}", video);
let s = serde_json::to_string(&video)?;
println!("json, {}", s);
let v: ApObject<Video> = serde_json::from_str(&s)?;
println!("Video again, {:#?}", v);
Ok(())
}
解析
use activitystreams::{activity::ActorAndObject, prelude::*};
#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub enum AcceptedTypes {
Accept,
Announce,
Create,
Delete,
Follow,
Reject,
Update,
Undo,
}
pub type AcceptedActivity = ActorAndObject<AcceptedTypes>;
pub fn handle_activity(activity: AcceptedActivity) -> Result<(), anyhow::Error> {
println!("Actor: {:?}", activity.actor());
println!("Object: {:?}", activity.object());
match activity.kind() {
Some(AcceptedTypes::Accept) => println!("Accept"),
Some(AcceptedTypes::Announce) => println!("Announce"),
Some(AcceptedTypes::Create) => println!("Create"),
Some(AcceptedTypes::Delete) => println!("Delete"),
Some(AcceptedTypes::Follow) => println!("Follow"),
Some(AcceptedTypes::Reject) => println!("Reject"),
Some(AcceptedTypes::Update) => println!("Update"),
Some(AcceptedTypes::Undo) => println!("Undo"),
None => return Err(anyhow::Error::msg("No activity type provided")),
}
Ok(())
}
static EXAMPLE_JSON: &str = r#"{"actor":"https://asonix.dog/users/asonix","object":"https://asonix.dog/users/asonix/posts/1","type":"Announce"}"#;
fn main() -> Result<(), anyhow::Error> {
handle_activity(serde_json::from_str(EXAMPLE_JSON)?)
}
贡献
如果您发现任何问题,请随时提交问题。请注意,任何贡献的代码都将根据GPLv3许可。
许可
版权 © 2020 Riley Trautman
ActivityStreams是自由软件:您可以按照自由软件基金会发布的GNU通用公共许可证的条款重新分发和/或修改它,许可证版本为3,或者(根据您的选择)任何更高版本。
ActivityStreams的发布是希望它将是有用的,但没有任何保证;甚至没有关于适销性或特定用途的隐含保证。有关详细信息,请参阅GNU通用公共许可证。此文件是ActivityStreams的一部分。
您应该已经收到ActivityStreams的GNU通用公共许可证副本。如果没有,请参阅http://www.gnu.org/licenses/。
依赖项
~1.9–2.7MB
~54K SLoC