mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-09-15 16:49:41 +02:00
feat: add function to assist parsing events
This commit is contained in:
@@ -109,7 +109,7 @@ func (em *eventManager) Emit(payload zoraxyPlugin.EventPayload) error {
|
||||
// Create the event
|
||||
event := zoraxyPlugin.Event{
|
||||
Name: eventName,
|
||||
Timestamp: time.Now(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
Data: payload,
|
||||
}
|
||||
|
||||
@@ -176,6 +176,17 @@ func (em *eventManager) dispatchToPlugin(pluginID string, event zoraxyPlugin.Eve
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
em.logger.PrintAndLog("event-system", "Plugin "+pluginID+" returned non-200 status for event: "+resp.Status, nil)
|
||||
respBody := fmt.Errorf("no response body")
|
||||
if resp.ContentLength > 0 {
|
||||
buffer := bytes.NewBuffer(make([]byte, 0, resp.ContentLength))
|
||||
_, respErr := buffer.ReadFrom(resp.Body)
|
||||
if respErr != nil {
|
||||
respBody = fmt.Errorf("failed to read response body: %v", respErr)
|
||||
} else {
|
||||
respBody = fmt.Errorf("response body: %s", buffer.String())
|
||||
}
|
||||
}
|
||||
|
||||
em.logger.PrintAndLog("event-system", fmt.Sprintf("Plugin %s returned non-200 status for event `%s`: %s", pluginID, event.Name, resp.Status), respBody)
|
||||
}
|
||||
}
|
||||
|
88
src/mod/plugins/event_system_test.go
Normal file
88
src/mod/plugins/event_system_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package plugins
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"imuslab.com/zoraxy/mod/plugins/zoraxy_plugin"
|
||||
)
|
||||
|
||||
// Test (de)serialization of events
|
||||
func TestEventDeSerialization(t *testing.T) {
|
||||
type SerializationTest struct {
|
||||
name string
|
||||
event zoraxy_plugin.Event
|
||||
expectedJson string
|
||||
}
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
|
||||
tests := []SerializationTest{
|
||||
{
|
||||
name: "BlacklistedIPBlocked",
|
||||
event: zoraxy_plugin.Event{
|
||||
Name: zoraxy_plugin.EventBlacklistedIPBlocked,
|
||||
Timestamp: timestamp,
|
||||
Data: &zoraxy_plugin.BlacklistedIPBlockedEvent{
|
||||
IP: "192.168.1.1",
|
||||
Comment: "Test comment",
|
||||
RequestedURL: "http://example.com",
|
||||
Hostname: "example.com",
|
||||
UserAgent: "TestUserAgent",
|
||||
Method: "GET",
|
||||
},
|
||||
},
|
||||
expectedJson: `{"name":"blacklistedIpBlocked","timestamp":` + fmt.Sprintf("%d", timestamp) + `,"data":{"ip":"192.168.1.1","comment":"Test comment","requested_url":"http://example.com","hostname":"example.com","user_agent":"TestUserAgent","method":"GET"}}`,
|
||||
},
|
||||
{
|
||||
name: "BlacklistToggled",
|
||||
event: zoraxy_plugin.Event{
|
||||
Name: zoraxy_plugin.EventBlacklistToggled,
|
||||
Timestamp: timestamp,
|
||||
Data: &zoraxy_plugin.BlacklistToggledEvent{
|
||||
RuleID: "rule123",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
expectedJson: `{"name":"blacklistToggled","timestamp":` + fmt.Sprintf("%d", timestamp) + `,"data":{"rule_id":"rule123","enabled":true}}`,
|
||||
},
|
||||
{
|
||||
name: "AccessRuleCreated",
|
||||
event: zoraxy_plugin.Event{
|
||||
Name: zoraxy_plugin.EventAccessRuleCreated,
|
||||
Timestamp: timestamp,
|
||||
Data: &zoraxy_plugin.AccessRuleCreatedEvent{
|
||||
ID: "rule456",
|
||||
Name: "New Access Rule",
|
||||
Desc: "A dummy access rule",
|
||||
BlacklistEnabled: true,
|
||||
WhitelistEnabled: false,
|
||||
},
|
||||
},
|
||||
expectedJson: `{"name":"accessRuleCreated","timestamp":` + fmt.Sprintf("%d", timestamp) + `,"data":{"id":"rule456","name":"New Access Rule","desc":"A dummy access rule","blacklist_enabled":true,"whitelist_enabled":false}}`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// Serialize the event
|
||||
jsonData, err := json.Marshal(test.event)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to serialize event: %v", err)
|
||||
}
|
||||
|
||||
// Compare the serialized JSON with the expected JSON
|
||||
if string(jsonData) != test.expectedJson {
|
||||
t.Fatalf("Unexpected JSON output.\nGot: %s\nWant: %s", jsonData, test.expectedJson)
|
||||
}
|
||||
|
||||
// Deserialize the JSON back into an event
|
||||
var deserializedEvent zoraxy_plugin.Event
|
||||
if err := zoraxy_plugin.ParseEvent(jsonData, &deserializedEvent); err != nil {
|
||||
t.Fatalf("Failed to parse event: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -157,9 +157,9 @@ func (m *Manager) StartPlugin(pluginID string) error {
|
||||
eventType := zoraxyPlugin.EventName(eventName)
|
||||
err := EventSystem.Subscribe(thisPlugin.Spec.ID, eventType)
|
||||
if err != nil {
|
||||
m.Log("Failed to subscribe plugin "+thisPlugin.Spec.Name+" to event "+eventName, err)
|
||||
m.Log("Failed to subscribe plugin "+thisPlugin.Spec.Name+" to event "+string(eventName), err)
|
||||
} else {
|
||||
m.Log("Subscribed plugin "+thisPlugin.Spec.Name+" to event "+eventName, nil)
|
||||
m.Log("Subscribed plugin "+thisPlugin.Spec.Name+" to event "+string(eventName), nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,8 @@
|
||||
package zoraxy_plugin
|
||||
|
||||
import (
|
||||
"time"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// EventName represents the type of event
|
||||
@@ -15,8 +16,8 @@ type EventPayload interface {
|
||||
|
||||
// Event represents a system event
|
||||
type Event struct {
|
||||
Name EventName `json:"type"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Name EventName `json:"name"`
|
||||
Timestamp int64 `json:"timestamp"` // Unix timestamp
|
||||
Data EventPayload `json:"data"`
|
||||
}
|
||||
|
||||
@@ -59,7 +60,7 @@ func (e *BlacklistToggledEvent) GetName() EventName {
|
||||
type AccessRuleCreatedEvent struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Desc string `json:"description"`
|
||||
Desc string `json:"desc"`
|
||||
BlacklistEnabled bool `json:"blacklist_enabled"`
|
||||
WhitelistEnabled bool `json:"whitelist_enabled"`
|
||||
}
|
||||
@@ -67,3 +68,44 @@ type AccessRuleCreatedEvent struct {
|
||||
func (e *AccessRuleCreatedEvent) GetName() EventName {
|
||||
return EventAccessRuleCreated
|
||||
}
|
||||
|
||||
// ParseEvent parses a JSON byte slice into an Event struct
|
||||
func ParseEvent(jsonData []byte, event *Event) error {
|
||||
// First, determine the event type, and parse shared fields, from the JSON data
|
||||
var temp struct {
|
||||
Name EventName `json:"name"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
if err := json.Unmarshal(jsonData, &temp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the event name and timestamp
|
||||
event.Name = temp.Name
|
||||
event.Timestamp = temp.Timestamp
|
||||
|
||||
// Now, based on the event type, unmarshal the specific payload
|
||||
switch temp.Name {
|
||||
case EventBlacklistedIPBlocked:
|
||||
var payload BlacklistedIPBlockedEvent
|
||||
if err := json.Unmarshal(jsonData, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Data = &payload
|
||||
case EventBlacklistToggled:
|
||||
var payload BlacklistToggledEvent
|
||||
if err := json.Unmarshal(jsonData, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Data = &payload
|
||||
case EventAccessRuleCreated:
|
||||
var payload AccessRuleCreatedEvent
|
||||
if err := json.Unmarshal(jsonData, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Data = &payload
|
||||
default:
|
||||
return fmt.Errorf("unknown event: %s, %v", temp.Name, jsonData)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -102,8 +102,8 @@ type IntroSpect struct {
|
||||
UIPath string `json:"ui_path"` //UI path of your plugin (e.g. /ui), will proxy the whole subpath tree to Zoraxy Web UI as plugin UI
|
||||
|
||||
/* Subscriptions Settings */
|
||||
SubscriptionPath string `json:"subscription_path"` //Subscription event path of your plugin (e.g. /notifyme), a POST request with SubscriptionEvent as body will be sent to this path when the event is triggered
|
||||
SubscriptionsEvents map[string]string `json:"subscriptions_events"` //Subscriptions events of your plugin, paired with comments describing how the event is used, see Zoraxy documentation for more details
|
||||
SubscriptionPath string `json:"subscription_path"` //Subscription event path of your plugin (e.g. /notifyme), a POST request with SubscriptionEvent as body will be sent to this path when the event is triggered
|
||||
SubscriptionsEvents map[EventName]string `json:"subscriptions_events"` //Subscriptions events of your plugin, paired with comments describing how the event is used, see Zoraxy documentation for more details
|
||||
|
||||
/* API Access Control */
|
||||
PermittedAPIEndpoints []PermittedAPIEndpoint `json:"permitted_api_endpoints"` //List of API endpoints this plugin can access, and a description of why the plugin needs to access this endpoint
|
||||
|
Reference in New Issue
Block a user