mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-29 15:51:20 +00:00
Proof of concept for Plugin system (fixes #3562)
This commit is contained in:
parent
7540b02723
commit
a65ccaf665
12 changed files with 4439 additions and 2295 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -34,3 +34,6 @@ dev_pgdata/
|
|||
|
||||
# database dumps
|
||||
*.sqldump
|
||||
|
||||
# compiled example plugin
|
||||
example_plugin/plugin.wasm
|
||||
|
|
1354
Cargo.lock
generated
1354
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -49,8 +49,6 @@ else
|
|||
done
|
||||
fi
|
||||
|
||||
echo "$PWD"
|
||||
|
||||
LOG_DIR=target/log
|
||||
mkdir -p $LOG_DIR
|
||||
|
||||
|
@ -75,6 +73,11 @@ LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_delta.hjson \
|
|||
LEMMY_DATABASE_URL="${LEMMY_DATABASE_URL}/lemmy_delta" \
|
||||
target/lemmy_server >$LOG_DIR/lemmy_delta.out 2>&1 &
|
||||
|
||||
# plugin setup
|
||||
pushd example_plugin
|
||||
tinygo build -o plugin.wasm -target wasi main.go
|
||||
popd
|
||||
|
||||
echo "start epsilon"
|
||||
# An instance who has a blocklist, with lemmy-alpha blocked
|
||||
LEMMY_CONFIG_LOCATION=./docker/federation/lemmy_epsilon.hjson \
|
||||
|
|
|
@ -11,7 +11,7 @@ killall -s1 lemmy_server || true
|
|||
popd
|
||||
|
||||
pnpm i
|
||||
pnpm api-test || true
|
||||
pnpm api-test-post || true
|
||||
|
||||
killall -s1 lemmy_server || true
|
||||
killall -s1 pict-rs || true
|
||||
|
|
|
@ -763,3 +763,14 @@ test("Fetch post with redirect", async () => {
|
|||
let gammaPost2 = await gamma.resolveObject(form);
|
||||
expect(gammaPost2.post).toBeDefined();
|
||||
});
|
||||
|
||||
test("Create a post", async () => {
|
||||
let community = await createCommunity(epsilon);
|
||||
let postRes = createPost(
|
||||
epsilon,
|
||||
community.community_view.community.id,
|
||||
"https://example.com/",
|
||||
"plugin should block this",
|
||||
);
|
||||
await expect(postRes).rejects.toStrictEqual(Error("plugin_error"));
|
||||
});
|
||||
|
|
|
@ -28,8 +28,11 @@ uuid = { workspace = true }
|
|||
moka.workspace = true
|
||||
once_cell.workspace = true
|
||||
anyhow.workspace = true
|
||||
serde.workspace = true
|
||||
webmention = "0.5.0"
|
||||
accept-language = "3.1.0"
|
||||
extism = "1.2.0"
|
||||
extism-convert = "1.2.0"
|
||||
|
||||
[package.metadata.cargo-machete]
|
||||
ignored = ["futures"]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use activitypub_federation::config::Data;
|
||||
use actix_web::web::Json;
|
||||
use extism::*;
|
||||
use lemmy_api_common::{
|
||||
build_response::build_post_response,
|
||||
context::LemmyContext,
|
||||
|
@ -46,6 +47,8 @@ use lemmy_utils::{
|
|||
},
|
||||
},
|
||||
};
|
||||
use serde::Serialize;
|
||||
use std::{ffi::OsStr, fs::read_dir};
|
||||
use tracing::Instrument;
|
||||
use url::Url;
|
||||
use webmention::{Webmention, WebmentionError};
|
||||
|
@ -123,6 +126,8 @@ pub async fn create_post(
|
|||
}
|
||||
};
|
||||
|
||||
plugin_hook("api_create_post", data.clone())?;
|
||||
|
||||
let post_form = PostInsertForm::builder()
|
||||
.name(data.name.trim().to_string())
|
||||
.url(url)
|
||||
|
@ -202,3 +207,31 @@ pub async fn create_post(
|
|||
|
||||
build_post_response(&context, community_id, &local_user_view.person, post_id).await
|
||||
}
|
||||
|
||||
fn load_plugins() -> LemmyResult<Plugin> {
|
||||
// TODO: make dir configurable via env var
|
||||
let plugin_paths = read_dir("example_plugin")?;
|
||||
|
||||
let mut wasm_files = vec![];
|
||||
for path in plugin_paths {
|
||||
let path = path?.path();
|
||||
if path.extension() == Some(OsStr::new("wasm")) {
|
||||
wasm_files.push(path);
|
||||
}
|
||||
}
|
||||
let manifest = Manifest::new(wasm_files);
|
||||
let plugin = Plugin::new(&manifest, [], true)?;
|
||||
Ok(plugin)
|
||||
}
|
||||
|
||||
fn plugin_hook<T: Serialize>(name: &'static str, data: T) -> LemmyResult<()> {
|
||||
let mut plugin = load_plugins()?;
|
||||
if plugin.function_exists(name) {
|
||||
let res = plugin
|
||||
.call::<extism_convert::Json<T>, &str>(name, data.into())
|
||||
.map_err(|e| LemmyErrorType::PluginError(e.to_string()));
|
||||
dbg!(&res);
|
||||
println!("{}", res?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -177,6 +177,7 @@ pub enum LemmyErrorType {
|
|||
InvalidBotAction,
|
||||
CantBlockLocalInstance,
|
||||
UrlWithoutDomain,
|
||||
PluginError(String),
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
|
|
5
example_plugin/go.mod
Normal file
5
example_plugin/go.mod
Normal file
|
@ -0,0 +1,5 @@
|
|||
module example_plugin
|
||||
|
||||
go 1.22.0
|
||||
|
||||
require github.com/extism/go-pdk v1.0.2 // indirect
|
2
example_plugin/go.sum
Normal file
2
example_plugin/go.sum
Normal file
|
@ -0,0 +1,2 @@
|
|||
github.com/extism/go-pdk v1.0.2 h1:UB7oTW3tw2zoMlsUdBEDAAbhQg9OudzgNeyCwQYZ730=
|
||||
github.com/extism/go-pdk v1.0.2/go.mod h1:Gz+LIU/YCKnKXhgge8yo5Yu1F/lbv7KtKFkiCSzW/P4=
|
32
example_plugin/main.go
Normal file
32
example_plugin/main.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/extism/go-pdk"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type CreatePost struct {
|
||||
Name string `json:"name"`
|
||||
Body string `json:"body"`
|
||||
// skipping other fields for now
|
||||
}
|
||||
|
||||
//export api_create_post
|
||||
func api_create_post() int32 {
|
||||
params := CreatePost{}
|
||||
// use json input helper, which automatically unmarshals the plugin input into your struct
|
||||
err := pdk.InputJSON(¶ms)
|
||||
if err != nil {
|
||||
pdk.SetError(err)
|
||||
return 1
|
||||
}
|
||||
if params.Body == "plugin should block this" {
|
||||
pdk.SetError(errors.New("blocked by plugin"))
|
||||
return 1
|
||||
}
|
||||
greeting := `Created post "` + params.Name + `"!`
|
||||
pdk.OutputString(greeting)
|
||||
return 0
|
||||
}
|
||||
|
||||
func main() {}
|
Loading…
Reference in a new issue