Added api doc

- Added zoraxy_plugin module api doc generating script
- Added link to example source folder
- Fixed a few minor typo
This commit is contained in:
Toby Chui 2025-05-31 14:23:11 +08:00
parent 0215171646
commit eec6cec0db
23 changed files with 822 additions and 24 deletions

View File

@ -3,4 +3,10 @@ go build
# Run the Go program with the specified arguments
./docs.exe -m=build
./docs.exe
echo "Running docs in development mode..."
./docs.exe
# After the docs web server mode terminate, rebuild it with root = plugins/html/
./docs.exe -m=build -root=plugins/html/
# The doc should always be ready to push to release branch

View File

@ -7,8 +7,6 @@ This example demonstrates how to use static capture in Zoraxy plugins. Static ca
**Notes: This example assumes you have already read Hello World example.**
Let's dive in!
---
## 1. Create the plugin folder structure

View File

@ -0,0 +1,257 @@
# Zoraxy Plugin APIs
This API documentation is auto-generated from the Zoraxy plugin source code.
<pre><code class='language-go'>
package zoraxy_plugin // import "{{your_module_package_name_in_go.mod}}/mod/plugins/zoraxy_plugin"
FUNCTIONS
func ServeIntroSpect(pluginSpect *IntroSpect)
ServeIntroSpect Function
This function will check if the plugin is initialized with -introspect flag,
if so, it will print the intro spect and exit
Place this function at the beginning of your plugin main function
TYPES
type ConfigureSpec struct {
Port int `json:"port"` //Port to listen
RuntimeConst RuntimeConstantValue `json:"runtime_const"` //Runtime constant values
}
ConfigureSpec Payload
Zoraxy will start your plugin with -configure flag, the plugin shell read
this payload as JSON and configure itself by the supplied values like
starting a web server at given port that listens to 127.0.0.1:port
func RecvConfigureSpec() (*ConfigureSpec, error)
RecvExecuteConfigureSpec Function
This function will read the configure spec from Zoraxy and return the
ConfigureSpec object
Place this function after ServeIntroSpect function in your plugin main
function
func ServeAndRecvSpec(pluginSpect *IntroSpect) (*ConfigureSpec, error)
ServeAndRecvSpec Function
This function will serve the intro spect and return the configure spec See
the ServeIntroSpect and RecvConfigureSpec for more details
type ControlStatusCode int
const (
ControlStatusCode_CAPTURED ControlStatusCode = 280 //Traffic captured by plugin, ask Zoraxy not to process the traffic
ControlStatusCode_UNHANDLED ControlStatusCode = 284 //Traffic not handled by plugin, ask Zoraxy to process the traffic
ControlStatusCode_ERROR ControlStatusCode = 580 //Error occurred while processing the traffic, ask Zoraxy to process the traffic and log the error
)
type DynamicSniffForwardRequest struct {
Method string `json:"method"`
Hostname string `json:"hostname"`
URL string `json:"url"`
Header map[string][]string `json:"header"`
RemoteAddr string `json:"remote_addr"`
Host string `json:"host"`
RequestURI string `json:"request_uri"`
Proto string `json:"proto"`
ProtoMajor int `json:"proto_major"`
ProtoMinor int `json:"proto_minor"`
// Has unexported fields.
}
Sniffing and forwarding
The following functions are here to help with
sniffing and forwarding requests to the dynamic
router.
A custom request object to be used in the dynamic sniffing
func DecodeForwardRequestPayload(jsonBytes []byte) (DynamicSniffForwardRequest, error)
DecodeForwardRequestPayload decodes JSON bytes into a
DynamicSniffForwardRequest object
func EncodeForwardRequestPayload(r *http.Request) DynamicSniffForwardRequest
GetForwardRequestPayload returns a DynamicSniffForwardRequest object from an
http.Request object
func (dsfr *DynamicSniffForwardRequest) GetRequest() *http.Request
GetRequest returns the original http.Request object, for debugging purposes
func (dsfr *DynamicSniffForwardRequest) GetRequestUUID() string
GetRequestUUID returns the request UUID if this UUID is empty string,
that might indicate the request is not coming from the dynamic router
type IntroSpect struct {
// Plugin metadata
ID string `json:"id"` //Unique ID of your plugin, recommended using your own domain in reverse like com.yourdomain.pluginname
Name string `json:"name"` //Name of your plugin
Author string `json:"author"` //Author name of your plugin
AuthorContact string `json:"author_contact"` //Author contact of your plugin, like email
Description string `json:"description"` //Description of your plugin
URL string `json:"url"` //URL of your plugin
Type PluginType `json:"type"` //Type of your plugin, Router(0) or Utilities(1)
VersionMajor int `json:"version_major"` //Major version of your plugin
VersionMinor int `json:"version_minor"` //Minor version of your plugin
VersionPatch int `json:"version_patch"` //Patch version of your plugin
// Static Capture Settings
//
// Once plugin is enabled these rules always applies to the enabled HTTP Proxy rule
// This is faster than dynamic capture, but less flexible
StaticCapturePaths []StaticCaptureRule `json:"static_capture_paths"` //Static capture paths of your plugin, see Zoraxy documentation for more details
StaticCaptureIngress string `json:"static_capture_ingress"` //Static capture ingress path of your plugin (e.g. /s_handler)
// Dynamic Capture Settings
//
// Once plugin is enabled, these rules will be captured and forward to plugin sniff
// if the plugin sniff returns 280, the traffic will be captured
// otherwise, the traffic will be forwarded to the next plugin
// This is slower than static capture, but more flexible
DynamicCaptureSniff string `json:"dynamic_capture_sniff"` //Dynamic capture sniff path of your plugin (e.g. /d_sniff)
DynamicCaptureIngress string `json:"dynamic_capture_ingress"` //Dynamic capture ingress path of your plugin (e.g. /d_handler)
// UI Path for your plugin
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, see Zoraxy documentation for more details
}
IntroSpect Payload
When the plugin is initialized with -introspect flag, the plugin shell
return this payload as JSON and exit
type PathRouter struct {
// Has unexported fields.
}
func NewPathRouter() *PathRouter
NewPathRouter creates a new PathRouter
func (p *PathRouter) PrintRequestDebugMessage(r *http.Request)
func (p *PathRouter) RegisterDynamicCaptureHandle(capture_ingress string, mux *http.ServeMux, handlefunc func(http.ResponseWriter, *http.Request))
RegisterDynamicCaptureHandle register the dynamic capture ingress path with
a handler
func (p *PathRouter) RegisterDynamicSniffHandler(sniff_ingress string, mux *http.ServeMux, handler SniffHandler)
RegisterDynamicSniffHandler registers a dynamic sniff handler for a path
You can decide to accept or skip the request based on the request header and
paths
func (p *PathRouter) RegisterPathHandler(path string, handler http.Handler)
RegisterPathHandler registers a handler for a path
func (p *PathRouter) RegisterStaticCaptureHandle(capture_ingress string, mux *http.ServeMux)
StartStaticCapture starts the static capture ingress
func (p *PathRouter) RemovePathHandler(path string)
RemovePathHandler removes a handler for a path
func (p *PathRouter) SetDebugPrintMode(enable bool)
SetDebugPrintMode sets the debug print mode
func (p *PathRouter) SetDefaultHandler(handler http.Handler)
SetDefaultHandler sets the default handler for the router This handler will
be called if no path handler is found
type PluginType int
const (
PluginType_Router PluginType = 0 //Router Plugin, used for handling / routing / forwarding traffic
PluginType_Utilities PluginType = 1 //Utilities Plugin, used for utilities like Zerotier or Static Web Server that do not require interception with the dpcore
)
type PluginUiDebugRouter struct {
PluginID string //The ID of the plugin
TargetDir string //The directory where the UI files are stored
HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui
EnableDebug bool //Enable debug mode
// Has unexported fields.
}
func NewPluginFileSystemUIRouter(pluginID string, targetDir string, handlerPrefix string) *PluginUiDebugRouter
NewPluginFileSystemUIRouter creates a new PluginUiRouter with file system
The targetDir is the directory where the UI files are stored (e.g. ./www)
The handlerPrefix is the prefix of the handler used to route this router
The handlerPrefix should start with a slash (e.g. /ui) that matches the
http.Handle path All prefix should not end with a slash
func (p *PluginUiDebugRouter) AttachHandlerToMux(mux *http.ServeMux)
Attach the file system UI handler to the target http.ServeMux
func (p *PluginUiDebugRouter) Handler() http.Handler
GetHttpHandler returns the http.Handler for the PluginUiRouter
func (p *PluginUiDebugRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux)
RegisterTerminateHandler registers the terminate handler for the
PluginUiRouter The terminate handler will be called when the plugin is
terminated from Zoraxy plugin manager if mux is nil, the handler will be
registered to http.DefaultServeMux
type PluginUiRouter struct {
PluginID string //The ID of the plugin
TargetFs *embed.FS //The embed.FS where the UI files are stored
TargetFsPrefix string //The prefix of the embed.FS where the UI files are stored, e.g. /web
HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui
EnableDebug bool //Enable debug mode
// Has unexported fields.
}
func NewPluginEmbedUIRouter(pluginID string, targetFs *embed.FS, targetFsPrefix string, handlerPrefix string) *PluginUiRouter
NewPluginEmbedUIRouter creates a new PluginUiRouter with embed.FS The
targetFsPrefix is the prefix of the embed.FS where the UI files are stored
The targetFsPrefix should be relative to the root of the embed.FS The
targetFsPrefix should start with a slash (e.g. /web) that corresponds to the
root folder of the embed.FS The handlerPrefix is the prefix of the handler
used to route this router The handlerPrefix should start with a slash (e.g.
/ui) that matches the http.Handle path All prefix should not end with a
slash
func (p *PluginUiRouter) AttachHandlerToMux(mux *http.ServeMux)
Attach the embed UI handler to the target http.ServeMux
func (p *PluginUiRouter) Handler() http.Handler
GetHttpHandler returns the http.Handler for the PluginUiRouter
func (p *PluginUiRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux)
RegisterTerminateHandler registers the terminate handler for the
PluginUiRouter The terminate handler will be called when the plugin is
terminated from Zoraxy plugin manager if mux is nil, the handler will be
registered to http.DefaultServeMux
type RuntimeConstantValue struct {
ZoraxyVersion string `json:"zoraxy_version"`
ZoraxyUUID string `json:"zoraxy_uuid"`
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
}
type SniffHandler func(*DynamicSniffForwardRequest) SniffResult
type SniffResult int
const (
SniffResultAccpet SniffResult = iota // Forward the request to this plugin dynamic capture ingress
SniffResultSkip // Skip this plugin and let the next plugin handle the request
)
type StaticCaptureRule struct {
CapturePath string `json:"capture_path"`
}
type SubscriptionEvent struct {
EventName string `json:"event_name"`
EventSource string `json:"event_source"`
Payload string `json:"payload"` //Payload of the event, can be empty
}
</code></pre>

View File

@ -0,0 +1,23 @@
#/bin/bash
# Cd into zoraxy plugin directory
cd ../../src/mod/plugins/zoraxy_plugin/
# Add header to the documentation
echo "# Zoraxy Plugin APIs" > docs.md
echo "This API documentation is auto-generated from the Zoraxy plugin source code." >> docs.md
echo "" >> docs.md
echo "" >> docs.md
echo "<pre><code class='language-go'>" >> docs.md
go doc -all >> docs.md
echo "</code></pre>" >> docs.md
# Replace // import "imuslab.com/zoraxy/mod/plugins/zoraxy_plugin" with
# // import "{{your_module_package_name_in_go.mod}}/mod/plugins/zoraxy_plugin"
sed -i 's|// import "imuslab.com/zoraxy/mod/plugins/zoraxy_plugin"|// import "{{your_module_package_name_in_go.mod}}/mod/plugins/zoraxy_plugin"|g' docs.md
# Move the generated docs to the plugins/html directory
mv docs.md "../../../../docs/plugins/docs/zoraxy_plugin API.md"
echo "Done generating Zoraxy plugin documentation."

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>
@ -175,9 +179,6 @@
</span>
</p>
</p>
<p>
Let&rsquo;s dive in!
</p>
<div class="ts-divider has-top-spaced-large"></div>
<h2 id="1-create-the-plugin-folder-structure">
1. Create the plugin folder structure

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -69,8 +69,9 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
@ -148,6 +149,9 @@
<a class="item is-active" href="/plugins/html/index.html">
index
</a>
<a class="item" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>

View File

@ -0,0 +1,448 @@
<!DOCTYPE html>
<html lang="en" class="is-white">
<head>
<meta charset="UTF-8">
<link rel="icon" type="image/png" href="/favicon.png">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>
zoraxy_plugin API | Zoraxy Documentation
</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/2.1.0/showdown.min.js" integrity="sha512-LhccdVNGe2QMEfI3x4DVV3ckMRe36TfydKss6mJpdHjNFiV07dFpS2xzeZedptKZrwxfICJpez09iNioiSZ3hA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tocas-ui/5.0.2/tocas.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/tocas-ui/5.0.2/tocas.min.js"></script>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@400;500;700&display=swap" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Code highlight -->
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/default.min.css"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/vs2015.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<!-- additional languages -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/go.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/c.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/javascript.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/css.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/xml.min.js"></script>
<style>
#msgbox{
position: fixed;
bottom: 1em;
right: 1em;
z-index: 9999;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
dialog[open] {
animation: fadeIn 0.3s ease-in-out;
}
code{
border-radius: 0.5rem;
}
</style>
<script src="/plugins/html/assets/theme.js"></script>
</head>
<body>
<div class="ts-content">
<div class="ts-container">
<div style="float: right;">
<button class="ts-button is-icon" id="darkModeToggle">
<span class="ts-icon is-moon-icon"></span>
</button>
</div>
<div class="ts-tab is-pilled">
<a href="" class="item" style="user-select: none;">
<img id="sysicon" class="ts-image" style="height: 30px" white_src="/plugins/html/assets/logo.png" dark_src="/plugins/html/assets/logo_white.png" src="/plugins/html/assets/logo.png"></img>
</a>
<a href="#!" class="is-active item">
Documents
</a>
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples
<span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>
</div>
<div class="ts-divider"></div>
<div>
<div class="has-padded">
<div class="ts-grid mobile:is-stacked">
<div class="column is-4-wide">
<div class="ts-box">
<div class="ts-menu is-end-icon">
<a class="item">
Introduction
<span class="ts-icon is-caret-down-icon"></span>
</a>
<div class="ts-menu is-dense is-small is-horizontally-padded">
<a class="item" href="/plugins/html/1. Introduction/1. What is Zoraxy Plugin.html">
What is Zoraxy Plugin
</a>
<a class="item" href="/plugins/html/1. Introduction/2. Getting Started.html">
Getting Started
</a>
<a class="item" href="/plugins/html/1. Introduction/3. Installing Plugin.html">
Installing Plugin
</a>
<a class="item" href="/plugins/html/1. Introduction/4. Enable Plugins.html">
Enable Plugins
</a>
<a class="item" href="/plugins/html/1. Introduction/5. Viewing Plugin Info.html">
Viewing Plugin Info
</a>
</div>
<a class="item">
Architecture
<span class="ts-icon is-caret-down-icon"></span>
</a>
<div class="ts-menu is-dense is-small is-horizontally-padded">
<a class="item" href="/plugins/html/2. Architecture/1. Plugin Architecture.html">
Plugin Architecture
</a>
<a class="item" href="/plugins/html/2. Architecture/2. Introspect.html">
Introspect
</a>
<a class="item" href="/plugins/html/2. Architecture/3. Configure.html">
Configure
</a>
<a class="item" href="/plugins/html/2. Architecture/4. Capture Modes.html">
Capture Modes
</a>
<a class="item" href="/plugins/html/2. Architecture/5. Plugin UI.html">
Plugin UI
</a>
<a class="item" href="/plugins/html/2. Architecture/6. Compile a Plugin.html">
Compile a Plugin
</a>
</div>
<a class="item">
Basic Examples
<span class="ts-icon is-caret-down-icon"></span>
</a>
<div class="ts-menu is-dense is-small is-horizontally-padded">
<a class="item" href="/plugins/html/3. Basic Examples/1. Hello World.html">
Hello World
</a>
<a class="item" href="/plugins/html/3. Basic Examples/2. RESTful Example.html">
RESTful Example
</a>
<a class="item" href="/plugins/html/3. Basic Examples/3. Static Capture Example.html">
Static Capture Example
</a>
<a class="item" href="/plugins/html/3. Basic Examples/4. Dynamic Capture Example.html">
Dynamic Capture Example
</a>
</div>
<a class="item" href="/plugins/html/index.html">
index
</a>
<a class="item is-active" href="/plugins/html/zoraxy_plugin API.html">
zoraxy_plugin API
</a>
</div>
</div>
</div>
<div class="column is-12-wide">
<div class="ts-box">
<div class="ts-container is-padded has-top-padded-large">
<h1 id="zoraxy-plugin-apis">
Zoraxy Plugin APIs
</h1>
<p>
<p class="ts-text">
This API documentation is auto-generated from the Zoraxy plugin source code.
</p>
</p>
<pre><code class='language-go'>
package zoraxy_plugin // import "{{your_module_package_name_in_go.mod}}/mod/plugins/zoraxy_plugin"
FUNCTIONS
func ServeIntroSpect(pluginSpect *IntroSpect)
ServeIntroSpect Function
This function will check if the plugin is initialized with -introspect flag,
if so, it will print the intro spect and exit
Place this function at the beginning of your plugin main function
TYPES
type ConfigureSpec struct {
Port int `json:"port"` //Port to listen
RuntimeConst RuntimeConstantValue `json:"runtime_const"` //Runtime constant values
}
ConfigureSpec Payload
Zoraxy will start your plugin with -configure flag, the plugin shell read
this payload as JSON and configure itself by the supplied values like
starting a web server at given port that listens to 127.0.0.1:port
func RecvConfigureSpec() (*ConfigureSpec, error)
RecvExecuteConfigureSpec Function
This function will read the configure spec from Zoraxy and return the
ConfigureSpec object
Place this function after ServeIntroSpect function in your plugin main
function
func ServeAndRecvSpec(pluginSpect *IntroSpect) (*ConfigureSpec, error)
ServeAndRecvSpec Function
This function will serve the intro spect and return the configure spec See
the ServeIntroSpect and RecvConfigureSpec for more details
type ControlStatusCode int
const (
ControlStatusCode_CAPTURED ControlStatusCode = 280 //Traffic captured by plugin, ask Zoraxy not to process the traffic
ControlStatusCode_UNHANDLED ControlStatusCode = 284 //Traffic not handled by plugin, ask Zoraxy to process the traffic
ControlStatusCode_ERROR ControlStatusCode = 580 //Error occurred while processing the traffic, ask Zoraxy to process the traffic and log the error
)
type DynamicSniffForwardRequest struct {
Method string `json:"method"`
Hostname string `json:"hostname"`
URL string `json:"url"`
Header map[string][]string `json:"header"`
RemoteAddr string `json:"remote_addr"`
Host string `json:"host"`
RequestURI string `json:"request_uri"`
Proto string `json:"proto"`
ProtoMajor int `json:"proto_major"`
ProtoMinor int `json:"proto_minor"`
// Has unexported fields.
}
Sniffing and forwarding
The following functions are here to help with
sniffing and forwarding requests to the dynamic
router.
A custom request object to be used in the dynamic sniffing
func DecodeForwardRequestPayload(jsonBytes []byte) (DynamicSniffForwardRequest, error)
DecodeForwardRequestPayload decodes JSON bytes into a
DynamicSniffForwardRequest object
func EncodeForwardRequestPayload(r *http.Request) DynamicSniffForwardRequest
GetForwardRequestPayload returns a DynamicSniffForwardRequest object from an
http.Request object
func (dsfr *DynamicSniffForwardRequest) GetRequest() *http.Request
GetRequest returns the original http.Request object, for debugging purposes
func (dsfr *DynamicSniffForwardRequest) GetRequestUUID() string
GetRequestUUID returns the request UUID if this UUID is empty string,
that might indicate the request is not coming from the dynamic router
type IntroSpect struct {
// Plugin metadata
ID string `json:"id"` //Unique ID of your plugin, recommended using your own domain in reverse like com.yourdomain.pluginname
Name string `json:"name"` //Name of your plugin
Author string `json:"author"` //Author name of your plugin
AuthorContact string `json:"author_contact"` //Author contact of your plugin, like email
Description string `json:"description"` //Description of your plugin
URL string `json:"url"` //URL of your plugin
Type PluginType `json:"type"` //Type of your plugin, Router(0) or Utilities(1)
VersionMajor int `json:"version_major"` //Major version of your plugin
VersionMinor int `json:"version_minor"` //Minor version of your plugin
VersionPatch int `json:"version_patch"` //Patch version of your plugin
// Static Capture Settings
//
// Once plugin is enabled these rules always applies to the enabled HTTP Proxy rule
// This is faster than dynamic capture, but less flexible
StaticCapturePaths []StaticCaptureRule `json:"static_capture_paths"` //Static capture paths of your plugin, see Zoraxy documentation for more details
StaticCaptureIngress string `json:"static_capture_ingress"` //Static capture ingress path of your plugin (e.g. /s_handler)
// Dynamic Capture Settings
//
// Once plugin is enabled, these rules will be captured and forward to plugin sniff
// if the plugin sniff returns 280, the traffic will be captured
// otherwise, the traffic will be forwarded to the next plugin
// This is slower than static capture, but more flexible
DynamicCaptureSniff string `json:"dynamic_capture_sniff"` //Dynamic capture sniff path of your plugin (e.g. /d_sniff)
DynamicCaptureIngress string `json:"dynamic_capture_ingress"` //Dynamic capture ingress path of your plugin (e.g. /d_handler)
// UI Path for your plugin
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, see Zoraxy documentation for more details
}
IntroSpect Payload
When the plugin is initialized with -introspect flag, the plugin shell
return this payload as JSON and exit
type PathRouter struct {
// Has unexported fields.
}
func NewPathRouter() *PathRouter
NewPathRouter creates a new PathRouter
func (p *PathRouter) PrintRequestDebugMessage(r *http.Request)
func (p *PathRouter) RegisterDynamicCaptureHandle(capture_ingress string, mux *http.ServeMux, handlefunc func(http.ResponseWriter, *http.Request))
RegisterDynamicCaptureHandle register the dynamic capture ingress path with
a handler
func (p *PathRouter) RegisterDynamicSniffHandler(sniff_ingress string, mux *http.ServeMux, handler SniffHandler)
RegisterDynamicSniffHandler registers a dynamic sniff handler for a path
You can decide to accept or skip the request based on the request header and
paths
func (p *PathRouter) RegisterPathHandler(path string, handler http.Handler)
RegisterPathHandler registers a handler for a path
func (p *PathRouter) RegisterStaticCaptureHandle(capture_ingress string, mux *http.ServeMux)
StartStaticCapture starts the static capture ingress
func (p *PathRouter) RemovePathHandler(path string)
RemovePathHandler removes a handler for a path
func (p *PathRouter) SetDebugPrintMode(enable bool)
SetDebugPrintMode sets the debug print mode
func (p *PathRouter) SetDefaultHandler(handler http.Handler)
SetDefaultHandler sets the default handler for the router This handler will
be called if no path handler is found
type PluginType int
const (
PluginType_Router PluginType = 0 //Router Plugin, used for handling / routing / forwarding traffic
PluginType_Utilities PluginType = 1 //Utilities Plugin, used for utilities like Zerotier or Static Web Server that do not require interception with the dpcore
)
type PluginUiDebugRouter struct {
PluginID string //The ID of the plugin
TargetDir string //The directory where the UI files are stored
HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui
EnableDebug bool //Enable debug mode
// Has unexported fields.
}
func NewPluginFileSystemUIRouter(pluginID string, targetDir string, handlerPrefix string) *PluginUiDebugRouter
NewPluginFileSystemUIRouter creates a new PluginUiRouter with file system
The targetDir is the directory where the UI files are stored (e.g. ./www)
The handlerPrefix is the prefix of the handler used to route this router
The handlerPrefix should start with a slash (e.g. /ui) that matches the
http.Handle path All prefix should not end with a slash
func (p *PluginUiDebugRouter) AttachHandlerToMux(mux *http.ServeMux)
Attach the file system UI handler to the target http.ServeMux
func (p *PluginUiDebugRouter) Handler() http.Handler
GetHttpHandler returns the http.Handler for the PluginUiRouter
func (p *PluginUiDebugRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux)
RegisterTerminateHandler registers the terminate handler for the
PluginUiRouter The terminate handler will be called when the plugin is
terminated from Zoraxy plugin manager if mux is nil, the handler will be
registered to http.DefaultServeMux
type PluginUiRouter struct {
PluginID string //The ID of the plugin
TargetFs *embed.FS //The embed.FS where the UI files are stored
TargetFsPrefix string //The prefix of the embed.FS where the UI files are stored, e.g. /web
HandlerPrefix string //The prefix of the handler used to route this router, e.g. /ui
EnableDebug bool //Enable debug mode
// Has unexported fields.
}
func NewPluginEmbedUIRouter(pluginID string, targetFs *embed.FS, targetFsPrefix string, handlerPrefix string) *PluginUiRouter
NewPluginEmbedUIRouter creates a new PluginUiRouter with embed.FS The
targetFsPrefix is the prefix of the embed.FS where the UI files are stored
The targetFsPrefix should be relative to the root of the embed.FS The
targetFsPrefix should start with a slash (e.g. /web) that corresponds to the
root folder of the embed.FS The handlerPrefix is the prefix of the handler
used to route this router The handlerPrefix should start with a slash (e.g.
/ui) that matches the http.Handle path All prefix should not end with a
slash
func (p *PluginUiRouter) AttachHandlerToMux(mux *http.ServeMux)
Attach the embed UI handler to the target http.ServeMux
func (p *PluginUiRouter) Handler() http.Handler
GetHttpHandler returns the http.Handler for the PluginUiRouter
func (p *PluginUiRouter) RegisterTerminateHandler(termFunc func(), mux *http.ServeMux)
RegisterTerminateHandler registers the terminate handler for the
PluginUiRouter The terminate handler will be called when the plugin is
terminated from Zoraxy plugin manager if mux is nil, the handler will be
registered to http.DefaultServeMux
type RuntimeConstantValue struct {
ZoraxyVersion string `json:"zoraxy_version"`
ZoraxyUUID string `json:"zoraxy_uuid"`
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
}
type SniffHandler func(*DynamicSniffForwardRequest) SniffResult
type SniffResult int
const (
SniffResultAccpet SniffResult = iota // Forward the request to this plugin dynamic capture ingress
SniffResultSkip // Skip this plugin and let the next plugin handle the request
)
type StaticCaptureRule struct {
CapturePath string `json:"capture_path"`
}
type SubscriptionEvent struct {
EventName string `json:"event_name"`
EventSource string `json:"event_source"`
Payload string `json:"payload"` //Payload of the event, can be empty
}
</code></pre>
</div>
<br>
<br>
</div>
</div>
</div>
</div>
</div>
<div class="ts-container">
<div class="ts-divider"></div>
<div class="ts-content">
<div class="ts-text">
Zoraxy © tobychui
<span class="thisyear">
2025
</span>
</div>
</div>
</div>
<script>
$(".thisyear").text(new Date().getFullYear());
</script>
<script>
hljs.highlightAll();
</script>
</body>
</html>

View File

@ -103,6 +103,11 @@
"filename": "index.md",
"title": "index",
"type": "file"
},
{
"filename": "zoraxy_plugin API.md",
"title": "zoraxy_plugin API",
"type": "file"
}
]
}

View File

@ -71,8 +71,8 @@
<a href="#!" class="is-active item">
Documents
</a>
<a href="#!" class="item">
Examples
<a href="https://github.com/tobychui/zoraxy/tree/main/example/plugins" target="_blank" class="item">
Examples <span class="ts-icon is-arrow-up-right-from-square-icon"></span>
</a>
</div>
</div>