mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2026-10-19 16:14:39 +00:00
feature (plg/extension): expand rust plugin footprint
This commit is contained in:
@@ -70,7 +70,7 @@ func (in *Instance) Http() func(*mux.Router) error {
|
||||
}
|
||||
router.HandleFunc(rt.path, middleware.NewMiddlewareChain(
|
||||
func(app *App, w http.ResponseWriter, r *http.Request) {
|
||||
if err := in.rt.Call(r.Context(), "http", httpKey{}, &httpData{r: r, w: w, ctx: app}); err != nil {
|
||||
if err := in.rt.Call(withHttp(r.Context(), app, w, r), "http", nil, nil); err != nil {
|
||||
utils.Log.Error("extension::adapter http path=%s err=%s", r.URL.Path, err.Error())
|
||||
}
|
||||
},
|
||||
|
||||
@@ -21,6 +21,7 @@ func NewInstance(wasm []byte, permissions ...string) (*Instance, error) {
|
||||
}
|
||||
rt, err := runtime.New(wasm, append(opts, runtime.WithExports(func(b *runtime.HostModuleBuilder) {
|
||||
exportShared(b)
|
||||
exportAuthentication(b)
|
||||
exportAuthorisation(b)
|
||||
exportMiddleware(b)
|
||||
exportHttp(b)
|
||||
@@ -46,7 +47,6 @@ type httpData struct {
|
||||
ctx *App
|
||||
r *http.Request
|
||||
w http.ResponseWriter
|
||||
next bool
|
||||
}
|
||||
|
||||
func stateHttp(ctx context.Context) *httpData {
|
||||
@@ -54,6 +54,10 @@ func stateHttp(ctx context.Context) *httpData {
|
||||
return d
|
||||
}
|
||||
|
||||
func withHttp(ctx context.Context, app *App, w http.ResponseWriter, r *http.Request) context.Context {
|
||||
return context.WithValue(ctx, httpKey{}, &httpData{ctx: app, r: r, w: w})
|
||||
}
|
||||
|
||||
func exportShared(b *runtime.HostModuleBuilder) {
|
||||
b.Export("log", func(ctx context.Context, mem runtime.IMemory, level, ptr, length uint32) {
|
||||
msg := string(mem.Read(ptr, length))
|
||||
|
||||
@@ -10,18 +10,28 @@ import (
|
||||
"github.com/mickael-kerjean/filestash/server/pkg/utils"
|
||||
)
|
||||
|
||||
type middlewareKey struct{}
|
||||
type middlewareData struct {
|
||||
next bool
|
||||
}
|
||||
|
||||
func stateMiddleware(ctx context.Context) *middlewareData {
|
||||
d, _ := ctx.Value(middlewareKey{}).(*middlewareData)
|
||||
return d
|
||||
}
|
||||
|
||||
func exportMiddleware(b *runtime.HostModuleBuilder) {
|
||||
b.Export("ffi_middleware_push_next", func(ctx context.Context) {
|
||||
stateHttp(ctx).next = true
|
||||
stateMiddleware(ctx).next = true
|
||||
})
|
||||
}
|
||||
|
||||
func (in *Instance) Middleware() func(HandlerFunc) HandlerFunc {
|
||||
return func(next HandlerFunc) HandlerFunc {
|
||||
return func(app *App, w http.ResponseWriter, r *http.Request) {
|
||||
hd := &httpData{r: r, w: w}
|
||||
err := in.rt.Call(r.Context(), "middleware", httpKey{}, hd)
|
||||
if errors.Is(err, runtime.ErrNoExport) || hd.next {
|
||||
md := middlewareData{next: false}
|
||||
err := in.rt.Call(withHttp(r.Context(), app, w, r), "middleware", middlewareKey{}, &md)
|
||||
if errors.Is(err, runtime.ErrNoExport) || md.next {
|
||||
next(app, w, r)
|
||||
return
|
||||
} else if err != nil {
|
||||
|
||||
@@ -70,8 +70,10 @@ func (r *Runtime) Call(ctx context.Context, fnName string, key, val any) error {
|
||||
}
|
||||
if fn == nil {
|
||||
return fmt.Errorf("%w: %s", ErrNoExport, fnName)
|
||||
} else if key != nil {
|
||||
ctx = context.WithValue(ctx, key, val)
|
||||
}
|
||||
_, err := fn.Call(context.WithValue(ctx, key, val))
|
||||
_, err := fn.Call(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,14 @@ func Discovery() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if in.Provides("authentication") {
|
||||
impl := in.Authentication()
|
||||
for _, elmnt := range impl.Setup().Elmnts {
|
||||
if elmnt.Name == "type" {
|
||||
Hooks.Register.AuthenticationMiddleware(fmt.Sprintf("%s", elmnt.Value), impl)
|
||||
}
|
||||
}
|
||||
}
|
||||
if in.Provides("authorisation") {
|
||||
Hooks.Register.AuthorisationMiddleware(in.Authorisation())
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
mockall = { version = "0.13", optional = true }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -61,6 +61,35 @@ macro_rules! register {
|
||||
}
|
||||
};
|
||||
|
||||
(@capability $anchor:ident, $app:ident, Authentication) => {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn capability_authentication() {}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn authentication_setup() {
|
||||
$crate::authentication::authentication_push_setup(
|
||||
&<$app as $crate::Authentication>::setup(),
|
||||
);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn authentication_entrypoint() {
|
||||
let idp = $crate::authentication::authentication_pull_idp();
|
||||
let mut res = $crate::ResponseImpl;
|
||||
if let Err(err) = <$app as $crate::Authentication>::entrypoint(idp, &$crate::RequestImpl, &mut res) {
|
||||
$crate::authentication::authentication_push_error(&err);
|
||||
}
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn authentication_callback() {
|
||||
let form = $crate::authentication::authentication_pull_form();
|
||||
let idp = $crate::authentication::authentication_pull_idp();
|
||||
let mut res = $crate::ResponseImpl;
|
||||
match <$app as $crate::Authentication>::callback(form, idp, &mut res) {
|
||||
Ok(session) => $crate::authentication::authentication_push_session(&session),
|
||||
Err(err) => $crate::authentication::authentication_push_error(&err),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(@capability $anchor:ident, $app:ident, Http) => {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn capability_http() {}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod app;
|
||||
pub mod authorisation;
|
||||
pub mod authentication;
|
||||
mod context;
|
||||
mod ffi;
|
||||
mod http;
|
||||
@@ -8,14 +9,19 @@ pub mod logger;
|
||||
mod middleware;
|
||||
mod request;
|
||||
mod response;
|
||||
mod form;
|
||||
mod error;
|
||||
|
||||
pub use authorisation::{Authorisation, Decision};
|
||||
pub use authentication::{Authentication};
|
||||
pub use http::{Handler, Http, Router};
|
||||
pub use lifecycle::{Lifecycle, OnChanges, OnDestroy, OnInit};
|
||||
pub use middleware::{Middleware, Next};
|
||||
pub use request::{Request, RequestImpl};
|
||||
pub use response::{Response, ResponseImpl};
|
||||
pub use context::{Context, ContextImpl};
|
||||
pub use form::{Form};
|
||||
pub use error::{Error};
|
||||
|
||||
pub use log;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ all:
|
||||
$(MAKE) -C permission_sock
|
||||
$(MAKE) -C permission_fs
|
||||
$(MAKE) -C authorisation
|
||||
$(MAKE) -C authentication
|
||||
zip -j cookbook.zip manifest.json \
|
||||
http/$(RELEASE)/endpoint.wasm \
|
||||
onInit/$(RELEASE)/oninit.wasm \
|
||||
@@ -15,7 +16,8 @@ all:
|
||||
onQuit/$(RELEASE)/onquit.wasm \
|
||||
permission_sock/$(RELEASE)/socket.wasm \
|
||||
permission_fs/$(RELEASE)/filesystem.wasm \
|
||||
authorisation/$(RELEASE)/authorisation.wasm
|
||||
authorisation/$(RELEASE)/authorisation.wasm \
|
||||
authentication/$(RELEASE)/authentication.wasm
|
||||
mv cookbook.zip ../../../dist/data/state/plugins/
|
||||
|
||||
init:
|
||||
@@ -30,3 +32,4 @@ clean:
|
||||
$(MAKE) -C permission_sock clean
|
||||
$(MAKE) -C permission_fs clean
|
||||
$(MAKE) -C authorisation clean
|
||||
$(MAKE) -C authentication clean
|
||||
|
||||
@@ -4,13 +4,13 @@ use filestash::*;
|
||||
pub struct Plugin;
|
||||
|
||||
impl Authorisation for Plugin {
|
||||
fn ls(&self, _ctx: &Context, path: &str) -> Decision {
|
||||
fn ls(&self, _ctx: &impl Context, path: &str) -> Decision {
|
||||
self.check(path)
|
||||
}
|
||||
fn cat(&self, _ctx: &Context, path: &str) -> Decision {
|
||||
fn cat(&self, _ctx: &impl Context, path: &str) -> Decision {
|
||||
self.check(path)
|
||||
}
|
||||
fn stat(&self, _ctx: &Context, path: &str) -> Decision {
|
||||
fn stat(&self, _ctx: &impl Context, path: &str) -> Decision {
|
||||
self.check(path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,9 @@ impl Http for Page {
|
||||
}
|
||||
|
||||
impl Page {
|
||||
fn index(&self, _req: &Request, res: &mut Response) {
|
||||
res.header("Content-Type", "text/html; charset=utf-8")
|
||||
.status(200)
|
||||
.write(b"<!DOCTYPE html><h1>Hello from a Filestash plugin</h1>");
|
||||
fn index(&self, _ctx: &impl Context, _req: &impl Request, res: &mut impl Response) {
|
||||
res.header("Content-Type", "text/html");
|
||||
res.write(b"<h1>Hello from a Filestash plugin</h1>");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
{ "type": "abi", "entrypoint": "onquit.wasm" },
|
||||
{ "type": "abi", "entrypoint": "socket.wasm" },
|
||||
{ "type": "abi", "entrypoint": "filesystem.wasm" },
|
||||
{ "type": "abi", "entrypoint": "authentication.wasm" },
|
||||
{ "type": "abi", "entrypoint": "authorisation.wasm" }
|
||||
],
|
||||
"permissions": [
|
||||
|
||||
Reference in New Issue
Block a user