-
Notifications
You must be signed in to change notification settings - Fork 253
feat: Add plugin system #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit
Hold shift + click to select a range
6253afe
Add devcontainer support
tutman96 7bc6516
Add dev:device script and support for setting JETKVM_PROXY_URL for de…
tutman96 377c3e8
Implement plugin upload support and placeholder settings item
tutman96 0a77200
Add extracting and validating the plugin
tutman96 00fdbaf
Write plugin database to tmp file first
tutman96 3853b58
Implement pluginList RPC and associated UI
tutman96 88f3e97
Add enable/disable button
tutman96 5de7bc7
Add process_manager and subprocess spawning support
tutman96 2ffb463
Handle "errored" condition instead of "stopped"
tutman96 5a05719
When tar extraction fails, delete extraction folder
tutman96 79305da
Fix net Listener interface and implement max process backoff time
tutman96 5652e8f
Fix bad pointer reference
tutman96 562f6c4
Add ability to uninstall a plugin
tutman96 e764000
Golang standards :)
tutman96 27b3395
Newlines for all things
tutman96 ce86105
Merge branch 'main' into plugin-system
tutman96 0b3cd59
Refactor jsonrpc server into its own package
tutman96 e61decf
wip: Plugin RPC with status reporting to the UI
tutman96 2428c15
Handle error conditions better and detect support methods automatically
tutman96 2e24916
Change wording from TODO to coming soon
tutman96 16064aa
Better handle install and re-install lifecycle. Also display all the …
tutman96 d1abc4b
Handle messages async to datachannel receive
tutman96 6fd978b
Rename JSONRPCServer to JSONRPCRouter
tutman96 ec20835
Fix jsonrpc references
tutman96 b9c871c
Merge branch 'dev' into plugin-system
tutman96 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "name": "JetKVM", | ||
| "image": "mcr.microsoft.com/devcontainers/go:1-1.23-bookworm", | ||
| "features": { | ||
| "ghcr.io/devcontainers/features/node:1": { | ||
| // Should match what is defined in ui/package.json | ||
| "version": "21.1.0" | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| package plugin | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "fmt" | ||
| "os" | ||
| "sync" | ||
| ) | ||
|
|
||
| const databaseFile = pluginsFolder + "/plugins.json" | ||
|
|
||
| type PluginDatabase struct { | ||
| // Map with the plugin name as the key | ||
| Plugins map[string]*PluginInstall `json:"plugins"` | ||
|
|
||
| saveMutex sync.Mutex | ||
| } | ||
|
|
||
| var pluginDatabase = PluginDatabase{} | ||
|
|
||
| func (d *PluginDatabase) Load() error { | ||
| file, err := os.Open(databaseFile) | ||
| if os.IsNotExist(err) { | ||
| d.Plugins = make(map[string]*PluginInstall) | ||
| return nil | ||
| } | ||
| if err != nil { | ||
| return fmt.Errorf("failed to open plugin database: %v", err) | ||
| } | ||
| defer file.Close() | ||
|
|
||
| if err := json.NewDecoder(file).Decode(d); err != nil { | ||
| return fmt.Errorf("failed to decode plugin database: %v", err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (d *PluginDatabase) Save() error { | ||
| d.saveMutex.Lock() | ||
| defer d.saveMutex.Unlock() | ||
|
|
||
| file, err := os.Create(databaseFile + ".tmp") | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create plugin database tmp: %v", err) | ||
| } | ||
| defer file.Close() | ||
|
|
||
| encoder := json.NewEncoder(file) | ||
| encoder.SetIndent("", " ") | ||
| if err := encoder.Encode(d); err != nil { | ||
| return fmt.Errorf("failed to encode plugin database: %v", err) | ||
| } | ||
|
|
||
| if err := os.Rename(databaseFile+".tmp", databaseFile); err != nil { | ||
| return fmt.Errorf("failed to move plugin database to active file: %v", err) | ||
| } | ||
|
|
||
| return nil | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| package plugin | ||
|
|
||
| import ( | ||
| "archive/tar" | ||
| "compress/gzip" | ||
| "fmt" | ||
| "io" | ||
| "os" | ||
| "path" | ||
| "path/filepath" | ||
| "strings" | ||
|
|
||
| "github.com/google/uuid" | ||
| ) | ||
|
|
||
| const pluginsExtractsFolder = pluginsFolder + "/extracts" | ||
|
|
||
| func init() { | ||
| _ = os.MkdirAll(pluginsExtractsFolder, 0755) | ||
| } | ||
|
|
||
| func extractPlugin(filePath string) (*string, error) { | ||
tutman96 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| file, err := os.Open(filePath) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to open file for extraction: %v", err) | ||
| } | ||
| defer file.Close() | ||
|
|
||
| var reader io.Reader = file | ||
| // TODO: there's probably a better way of doing this without relying on the file extension | ||
| if strings.HasSuffix(filePath, ".gz") { | ||
|
Comment on lines
+30
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Grabbing the first few bytes of the file and doing: can be a nicer way to handle this. |
||
| gzipReader, err := gzip.NewReader(file) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to create gzip reader: %v", err) | ||
| } | ||
| defer gzipReader.Close() | ||
| reader = gzipReader | ||
| } | ||
|
|
||
| destinationFolder := path.Join(pluginsExtractsFolder, uuid.New().String()) | ||
| if err := os.MkdirAll(destinationFolder, 0755); err != nil { | ||
| return nil, fmt.Errorf("failed to create extracts folder: %v", err) | ||
| } | ||
|
|
||
| tarReader := tar.NewReader(reader) | ||
|
|
||
| for { | ||
| header, err := tarReader.Next() | ||
| if err == io.EOF { | ||
| break | ||
| } | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to read tar header: %v", err) | ||
| } | ||
|
|
||
| // Prevent path traversal attacks | ||
| targetPath := filepath.Join(destinationFolder, header.Name) | ||
| if !strings.HasPrefix(targetPath, filepath.Clean(destinationFolder)+string(os.PathSeparator)) { | ||
| return nil, fmt.Errorf("tar file contains illegal path: %s", header.Name) | ||
| } | ||
|
|
||
| switch header.Typeflag { | ||
| case tar.TypeDir: | ||
| if err := os.MkdirAll(targetPath, os.FileMode(header.Mode)); err != nil { | ||
| return nil, fmt.Errorf("failed to create directory: %v", err) | ||
| } | ||
| case tar.TypeReg: | ||
| file, err := os.OpenFile(targetPath, os.O_CREATE|os.O_WRONLY, os.FileMode(header.Mode)) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to create file: %v", err) | ||
| } | ||
| defer file.Close() | ||
|
|
||
| if _, err := io.Copy(file, tarReader); err != nil { | ||
| return nil, fmt.Errorf("failed to extract file: %v", err) | ||
| } | ||
| default: | ||
| return nil, fmt.Errorf("unsupported tar entry type: %v", header.Typeflag) | ||
| } | ||
| } | ||
tutman96 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return &destinationFolder, nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.