Files
orly/pkg/protocol/socketapi/handleReq.go
mleku 651791aec1 Add export functionality and fix privilege checks
- Added `Export` method in `database/database.go` to export events to an io.Writer
- Implemented detailed logic for exporting all or specific pubkeys' events
- Removed placeholder `Export` function with TODO comment from `database/database.go`
- Updated error handling in `handleReq.go` and `publisher.go` by using `err != nil` instead of `chk.E(err)`
- Added more detailed logging in privilege check conditions in both `publisher.go` and `handleReq.go`
- Introduced new imports such as `"fmt"` in `connection.go` for improved error message formatting
- Created a new file `export.go` under the `database` package with complete implementation of export functionality
2025-07-22 11:34:57 +01:00

157 lines
3.9 KiB
Go

package socketapi
import (
"errors"
"github.com/dgraph-io/badger/v4"
"orly.dev/pkg/encoders/envelopes/closedenvelope"
"orly.dev/pkg/encoders/envelopes/eoseenvelope"
"orly.dev/pkg/encoders/envelopes/eventenvelope"
"orly.dev/pkg/encoders/envelopes/reqenvelope"
"orly.dev/pkg/encoders/event"
"orly.dev/pkg/interfaces/server"
"orly.dev/pkg/protocol/auth"
"orly.dev/pkg/utils/chk"
"orly.dev/pkg/utils/context"
"orly.dev/pkg/utils/log"
"orly.dev/pkg/utils/normalize"
"orly.dev/pkg/utils/pointers"
)
// HandleReq processes a raw request, parses its envelope, validates filters,
// and interacts with the server storage and subscription mechanisms to query
// events or manage subscriptions.
//
// # Parameters
//
// - c: a context object used for managing deadlines, cancellation signals,
// and other request-scoped values.
//
// - req: a byte slice representing the raw request data to be processed.
//
// - srv: An interface representing the server, providing access to storage
// and subscription management.
//
// # Return Values
//
// - r: a byte slice containing the response or error message generated
// during processing.
//
// # Expected behaviour
//
// The method parses and validates the incoming request envelope, querying
// events from the server storage based on filters provided. It sends results
// through the associated subscription or writes error messages to the listener.
// If the subscription should be cancelled due to completed query results, it
// generates and sends a closure envelope.
func (a *A) HandleReq(
c context.T, req []byte, srv server.I,
) (r []byte) {
var err error
log.I.F("REQ:\n%s", req)
sto := srv.Storage()
var rem []byte
env := reqenvelope.New()
if rem, err = env.Unmarshal(req); chk.E(err) {
return normalize.Error.F(err.Error())
}
if len(rem) > 0 {
log.I.F("extra '%s'", rem)
}
var accept bool
allowed, accept, _ := srv.AcceptReq(
c, a.Request, env.Filters, a.Listener.AuthedPubkey(),
a.Listener.RealRemote(),
)
if !accept {
if err = closedenvelope.NewFrom(
env.Subscription, []byte("filters aren't permitted for client"),
).Write(a.Listener); chk.E(err) {
return
}
return
}
var events event.S
for _, f := range allowed.F {
// var i uint
if pointers.Present(f.Limit) {
if *f.Limit == 0 {
continue
}
}
if events, err = sto.QueryEvents(c, f); err != nil {
if errors.Is(err, badger.ErrDBClosed) {
return
}
continue
}
// filter events the authed pubkey is not privileged to fetch.
if srv.AuthRequired() {
var tmp event.S
for _, ev := range events {
if !auth.CheckPrivilege(a.Listener.AuthedPubkey(), ev) {
log.W.F(
"not privileged %0x ev pubkey %0x kind %s privileged: %v",
a.Listener.AuthedPubkey(), ev.Pubkey, ev.Kind.Name(),
ev.Kind.IsPrivileged(),
)
continue
}
tmp = append(tmp, ev)
}
events = tmp
}
// write out the events to the socket
for _, ev := range events {
var res *eventenvelope.Result
if res, err = eventenvelope.NewResultWith(
env.Subscription.T,
ev,
); chk.E(err) {
return
}
if err = res.Write(a.Listener); chk.E(err) {
return
}
}
}
if err = eoseenvelope.NewFrom(env.Subscription).Write(a.Listener); chk.E(err) {
return
}
receiver := make(event.C, 32)
cancel := true
// if the query was for just Ids, we know there cannot be any more results,
// so cancel the subscription.
for _, f := range allowed.F {
if f.Ids.Len() < 1 {
cancel = false
break
}
// also, if we received the limit number of events, subscription ded
if pointers.Present(f.Limit) {
if len(events) < int(*f.Limit) {
cancel = false
}
}
if !cancel {
break
}
}
if !cancel {
srv.Publisher().Receive(
&W{
Listener: a.Listener,
Id: env.Subscription.String(),
Receiver: receiver,
Filters: env.Filters,
},
)
} else {
if err = closedenvelope.NewFrom(
env.Subscription, nil,
).Write(a.Listener); chk.E(err) {
return
}
}
return
}