new: Big Change, Add support for Extensions 😍
This commit is contained in:
@@ -1,54 +1,72 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hiddify/hiddify-core/extension/ui_elements"
|
||||
"github.com/hiddify/hiddify-core/common"
|
||||
"github.com/hiddify/hiddify-core/config"
|
||||
"github.com/hiddify/hiddify-core/extension/ui"
|
||||
pb "github.com/hiddify/hiddify-core/hiddifyrpc"
|
||||
)
|
||||
|
||||
var (
|
||||
extensionsMap = make(map[string]*Extension)
|
||||
extensionStatusMap = make(map[string]bool)
|
||||
"github.com/jellydator/validation"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
type Extension interface {
|
||||
GetTitle() string
|
||||
GetDescription() string
|
||||
GetUI() ui_elements.Form
|
||||
GetUI() ui.Form
|
||||
SubmitData(data map[string]string) error
|
||||
Cancel() error
|
||||
Stop() error
|
||||
UpdateUI(form ui_elements.Form) error
|
||||
UpdateUI(form ui.Form) error
|
||||
|
||||
BeforeAppConnect(hiddifySettings *config.HiddifyOptions, singconfig *option.Options) error
|
||||
|
||||
StoreData()
|
||||
|
||||
init(id string)
|
||||
getQueue() chan *pb.ExtensionResponse
|
||||
getId() string
|
||||
}
|
||||
|
||||
type BaseExtension struct {
|
||||
type Base[T any] struct {
|
||||
id string
|
||||
// responseStream grpc.ServerStreamingServer[pb.ExtensionResponse]
|
||||
queue chan *pb.ExtensionResponse
|
||||
Data T
|
||||
}
|
||||
|
||||
// func (b *BaseExtension) mustEmbdedBaseExtension() {
|
||||
// func (b *Base) mustEmbdedBaseExtension() {
|
||||
// }
|
||||
|
||||
func (b *BaseExtension) init(id string) {
|
||||
b.id = id
|
||||
b.queue = make(chan *pb.ExtensionResponse, 1)
|
||||
func (b *Base[T]) BeforeAppConnect(hiddifySettings *config.HiddifyOptions, singconfig *option.Options) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseExtension) getQueue() chan *pb.ExtensionResponse {
|
||||
func (b *Base[T]) StoreData() {
|
||||
common.Storage.SaveExtensionData(b.id, &b.Data)
|
||||
}
|
||||
|
||||
func (b *Base[T]) init(id string) {
|
||||
b.id = id
|
||||
b.queue = make(chan *pb.ExtensionResponse, 1)
|
||||
common.Storage.GetExtensionData(b.id, &b.Data)
|
||||
}
|
||||
|
||||
func (b *Base[T]) getQueue() chan *pb.ExtensionResponse {
|
||||
return b.queue
|
||||
}
|
||||
|
||||
func (b *BaseExtension) getId() string {
|
||||
func (b *Base[T]) getId() string {
|
||||
return b.id
|
||||
}
|
||||
|
||||
func (p *BaseExtension) UpdateUI(form ui_elements.Form) error {
|
||||
func (e *Base[T]) ShowMessage(title string, msg string) error {
|
||||
return e.ShowDialog(ui.Form{
|
||||
Title: title,
|
||||
Description: msg,
|
||||
Buttons: []string{ui.Button_Ok},
|
||||
})
|
||||
}
|
||||
|
||||
func (p *Base[T]) UpdateUI(form ui.Form) error {
|
||||
p.queue <- &pb.ExtensionResponse{
|
||||
ExtensionId: p.id,
|
||||
Type: pb.ExtensionResponseType_UPDATE_UI,
|
||||
@@ -57,7 +75,7 @@ func (p *BaseExtension) UpdateUI(form ui_elements.Form) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *BaseExtension) ShowDialog(form ui_elements.Form) error {
|
||||
func (p *Base[T]) ShowDialog(form ui.Form) error {
|
||||
p.queue <- &pb.ExtensionResponse{
|
||||
ExtensionId: p.id,
|
||||
Type: pb.ExtensionResponseType_SHOW_DIALOG,
|
||||
@@ -67,20 +85,22 @@ func (p *BaseExtension) ShowDialog(form ui_elements.Form) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RegisterExtension(id string, extension Extension) error {
|
||||
if _, ok := extensionsMap[id]; ok {
|
||||
err := fmt.Errorf("Extension with ID %s already exists", id)
|
||||
log.Fatal(err)
|
||||
return err
|
||||
func (base *Base[T]) ValName(fieldPtr interface{}) string {
|
||||
val, err := validation.ErrorFieldName(&base.Data, fieldPtr)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
return ""
|
||||
}
|
||||
if val, ok := extensionStatusMap[id]; ok && !val {
|
||||
err := fmt.Errorf("Extension with ID %s is not enabled", id)
|
||||
log.Fatal(err)
|
||||
return err
|
||||
if val == "" {
|
||||
log.Warn("Field not found")
|
||||
return ""
|
||||
}
|
||||
extension.init(id)
|
||||
|
||||
fmt.Printf("Registered extension: %+v\n", extension)
|
||||
extensionsMap[id] = &extension
|
||||
return nil
|
||||
return val
|
||||
}
|
||||
|
||||
type ExtensionFactory struct {
|
||||
Id string
|
||||
Title string
|
||||
Description string
|
||||
Builder func() Extension
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hiddify/hiddify-core/common"
|
||||
pb "github.com/hiddify/hiddify-core/hiddifyrpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
@@ -18,11 +19,12 @@ func (ExtensionHostService) ListExtensions(ctx context.Context, empty *pb.Empty)
|
||||
Extensions: make([]*pb.Extension, 0),
|
||||
}
|
||||
|
||||
for _, extension := range extensionsMap {
|
||||
for _, extension := range allExtensionsMap {
|
||||
extensionList.Extensions = append(extensionList.Extensions, &pb.Extension{
|
||||
Id: (*extension).getId(),
|
||||
Title: (*extension).GetTitle(),
|
||||
Description: (*extension).GetDescription(),
|
||||
Id: extension.Id,
|
||||
Title: extension.Title,
|
||||
Description: extension.Description,
|
||||
Enable: generalExtensionData.ExtensionStatusMap[extension.Id],
|
||||
})
|
||||
}
|
||||
return extensionList, nil
|
||||
@@ -30,7 +32,7 @@ func (ExtensionHostService) ListExtensions(ctx context.Context, empty *pb.Empty)
|
||||
|
||||
func (e ExtensionHostService) Connect(req *pb.ExtensionRequest, stream grpc.ServerStreamingServer[pb.ExtensionResponse]) error {
|
||||
// Get the extension from the map using the Extension ID
|
||||
if extension, ok := extensionsMap[req.GetExtensionId()]; ok {
|
||||
if extension, ok := enabledExtensionsMap[req.GetExtensionId()]; ok {
|
||||
|
||||
log.Printf("Connecting stream for extension %s", req.GetExtensionId())
|
||||
log.Printf("Extension data: %+v", extension)
|
||||
@@ -100,7 +102,7 @@ func (e ExtensionHostService) Connect(req *pb.ExtensionRequest, stream grpc.Serv
|
||||
}
|
||||
|
||||
func (e ExtensionHostService) SubmitForm(ctx context.Context, req *pb.ExtensionRequest) (*pb.ExtensionActionResult, error) {
|
||||
if extension, ok := extensionsMap[req.GetExtensionId()]; ok {
|
||||
if extension, ok := enabledExtensionsMap[req.GetExtensionId()]; ok {
|
||||
(*extension).SubmitData(req.GetData())
|
||||
|
||||
return &pb.ExtensionActionResult{
|
||||
@@ -113,7 +115,7 @@ func (e ExtensionHostService) SubmitForm(ctx context.Context, req *pb.ExtensionR
|
||||
}
|
||||
|
||||
func (e ExtensionHostService) Cancel(ctx context.Context, req *pb.ExtensionRequest) (*pb.ExtensionActionResult, error) {
|
||||
if extension, ok := extensionsMap[req.GetExtensionId()]; ok {
|
||||
if extension, ok := enabledExtensionsMap[req.GetExtensionId()]; ok {
|
||||
(*extension).Cancel()
|
||||
|
||||
return &pb.ExtensionActionResult{
|
||||
@@ -126,9 +128,9 @@ func (e ExtensionHostService) Cancel(ctx context.Context, req *pb.ExtensionReque
|
||||
}
|
||||
|
||||
func (e ExtensionHostService) Stop(ctx context.Context, req *pb.ExtensionRequest) (*pb.ExtensionActionResult, error) {
|
||||
if extension, ok := extensionsMap[req.GetExtensionId()]; ok {
|
||||
if extension, ok := enabledExtensionsMap[req.GetExtensionId()]; ok {
|
||||
(*extension).Stop()
|
||||
|
||||
(*extension).StoreData()
|
||||
return &pb.ExtensionActionResult{
|
||||
ExtensionId: req.ExtensionId,
|
||||
Code: pb.ResponseCode_OK,
|
||||
@@ -137,3 +139,24 @@ func (e ExtensionHostService) Stop(ctx context.Context, req *pb.ExtensionRequest
|
||||
}
|
||||
return nil, fmt.Errorf("Extension with ID %s not found", req.GetExtensionId())
|
||||
}
|
||||
|
||||
func (e ExtensionHostService) EditExtension(ctx context.Context, req *pb.EditExtensionRequest) (*pb.ExtensionActionResult, error) {
|
||||
generalExtensionData.ExtensionStatusMap[req.GetExtensionId()] = req.Enable
|
||||
if !req.Enable {
|
||||
ext := *enabledExtensionsMap[req.GetExtensionId()]
|
||||
if ext != nil {
|
||||
ext.Stop()
|
||||
ext.StoreData()
|
||||
}
|
||||
delete(enabledExtensionsMap, req.GetExtensionId())
|
||||
} else {
|
||||
loadExtension(allExtensionsMap[req.GetExtensionId()])
|
||||
}
|
||||
common.Storage.SaveExtensionData("default", generalExtensionData)
|
||||
|
||||
return &pb.ExtensionActionResult{
|
||||
ExtensionId: req.ExtensionId,
|
||||
Code: pb.ResponseCode_OK,
|
||||
Message: "Success",
|
||||
}, nil
|
||||
}
|
||||
|
||||
12
extension/html/a.js
Normal file
12
extension/html/a.js
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
import * as a from "./rpc/extension_grpc_web_pb.js";
|
||||
const client = new ExtensionHostServiceClient('http://localhost:8080');
|
||||
const request = new GetHelloRequest();
|
||||
export const getHello = (name) => {
|
||||
request.setName(name)
|
||||
client.getHello(request, {}, (err, response) => {
|
||||
console.log(request.getName());
|
||||
console.log(response.toObject());
|
||||
});
|
||||
}
|
||||
getHello("D")
|
||||
@@ -8,18 +8,49 @@
|
||||
|
||||
|
||||
<style>
|
||||
.monospace { font-family: monospace; }
|
||||
pre {
|
||||
background-color: black !important; overflow: auto;
|
||||
color: white!important; }
|
||||
</style>
|
||||
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<div id="extension-list-container">
|
||||
<div id="connection-page" class="card p-4">
|
||||
<div id="connection-before-connect" class="card-body">
|
||||
<h2 class="card-title mb-4">Connection Settings</h2>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="config-content" class="form-label">Config String</label>
|
||||
<textarea id="config-content" class="form-control" placeholder="Enter config string here..." rows="3"></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="hiddify-settings" class="form-label">Hiddify Settings</label>
|
||||
<textarea id="hiddify-settings" class="form-control" placeholder="Enter Hiddify settings here..." rows="3"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between">
|
||||
<button id="connect-button" class="btn btn-success">Connect</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="connection-connecting" class="card-body d-none">
|
||||
<h2 id="connection-status" class="card-title mb-4">Connecting...</h2>
|
||||
<button id="disconnect-button" class="btn btn-danger">Disconnect</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="extension-list-container" class="card p-4">
|
||||
<h1 class="mb-4">
|
||||
Extension List
|
||||
</h1>
|
||||
<div id="extension-list" class="list-group">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="extension-page-container" style="display: none;">
|
||||
<div id="extension-page-container" class="card p-4">
|
||||
|
||||
<div id="extension-page"></div>
|
||||
</div>
|
||||
@@ -41,7 +72,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/ansi_up@5.0.0/ansi_up.js"></script>
|
||||
<script src="https://unpkg.com/google-protobuf@3.20.1/dist/google-protobuf.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/protobufjs@7.X.X/dist/protobuf.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.3/js/bootstrap.bundle.min.js" integrity="sha512-7Pi/otdlbbCR+LnW+F7PwFcSDJOuUJB3OxtEHbg4vSMvzvJjde4Po1v4BR9Gdc9aXNUNFVUY+SK51wWT8WF0Gg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
||||
const hiddify = require("./hiddify_grpc_web_pb.js");
|
||||
const extension = require("./extension_grpc_web_pb.js");
|
||||
|
||||
const grpcServerAddress = '/';
|
||||
const client = new extension.ExtensionHostServicePromiseClient(grpcServerAddress, null, null);
|
||||
const extensionClient = new extension.ExtensionHostServicePromiseClient(grpcServerAddress, null, null);
|
||||
const hiddifyClient = new hiddify.CorePromiseClient(grpcServerAddress, null, null);
|
||||
|
||||
module.exports = { client ,extension};
|
||||
module.exports = { extensionClient ,hiddifyClient};
|
||||
109
extension/html/rpc/connectionPage.js
Normal file
109
extension/html/rpc/connectionPage.js
Normal file
@@ -0,0 +1,109 @@
|
||||
const { hiddifyClient } = require('./client.js');
|
||||
const hiddify = require("./hiddify_grpc_web_pb.js");
|
||||
|
||||
function openConnectionPage() {
|
||||
|
||||
$("#extension-list-container").show();
|
||||
$("#extension-page-container").hide();
|
||||
$("#connection-page").show();
|
||||
connect();
|
||||
$("#connect-button").click(async () => {
|
||||
const hsetting_request = new hiddify.ChangeHiddifySettingsRequest();
|
||||
hsetting_request.setHiddifySettingsJson($("#hiddify-settings").val());
|
||||
try{
|
||||
const hres=await hiddifyClient.changeHiddifySettings(hsetting_request, {});
|
||||
}catch(err){
|
||||
$("#hiddify-settings").val("")
|
||||
console.log(err)
|
||||
}
|
||||
|
||||
const parse_request = new hiddify.ParseRequest();
|
||||
parse_request.setContent($("#config-content").val());
|
||||
try{
|
||||
const pres=await hiddifyClient.parse(parse_request, {});
|
||||
if (pres.getResponseCode() !== hiddify.ResponseCode.OK){
|
||||
alert(pres.getMessage());
|
||||
return
|
||||
}
|
||||
$("#config-content").val(pres.getContent());
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
alert(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
|
||||
const request = new hiddify.StartRequest();
|
||||
|
||||
request.setConfigContent($("#config-content").val());
|
||||
request.setEnableRawConfig(false);
|
||||
try{
|
||||
const res=await hiddifyClient.start(request, {});
|
||||
console.log(res.getCoreState(),res.getMessage())
|
||||
handleCoreStatus(res.getCoreState());
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
alert(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
||||
$("#disconnect-button").click(async () => {
|
||||
const request = new hiddify.Empty();
|
||||
try{
|
||||
const res=await hiddifyClient.stop(request, {});
|
||||
console.log(res.getCoreState(),res.getMessage())
|
||||
handleCoreStatus(res.getCoreState());
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
alert(JSON.stringify(err))
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function connect(){
|
||||
const request = new hiddify.Empty();
|
||||
const stream = hiddifyClient.coreInfoListener(request, {});
|
||||
stream.on('data', (response) => {
|
||||
console.log('Receving ',response);
|
||||
handleCoreStatus(response);
|
||||
});
|
||||
|
||||
stream.on('error', (err) => {
|
||||
console.error('Error opening extension page:', err);
|
||||
// openExtensionPage(extensionId);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
console.log('Stream ended');
|
||||
setTimeout(connect, 1000);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function handleCoreStatus(status){
|
||||
if (status == hiddify.CoreState.STOPPED){
|
||||
$("#connection-before-connect").show();
|
||||
$("#connection-connecting").hide();
|
||||
}else{
|
||||
$("#connection-before-connect").hide();
|
||||
$("#connection-connecting").show();
|
||||
if (status == hiddify.CoreState.STARTING){
|
||||
$("#connection-status").text("Starting");
|
||||
$("#connection-status").css("color", "yellow");
|
||||
}else if (status == hiddify.CoreState.STOPPING){
|
||||
$("#connection-status").text("Stopping");
|
||||
$("#connection-status").css("color", "red");
|
||||
}else if (status == hiddify.CoreState.STARTED){
|
||||
$("#connection-status").text("Connected");
|
||||
$("#connection-status").css("color", "green");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = { openConnectionPage };
|
||||
@@ -1,7 +1,8 @@
|
||||
const { listExtensions } = require('./extensionList.js');
|
||||
|
||||
const { openConnectionPage } = require('./connectionPage.js');
|
||||
window.onload = () => {
|
||||
listExtensions();
|
||||
openConnectionPage();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
|
||||
const { client,extension } = require('./client.js');
|
||||
const { extensionClient } = require('./client.js');
|
||||
const extension = require("./extension_grpc_web_pb.js");
|
||||
async function listExtensions() {
|
||||
$("#extension-list-container").show();
|
||||
$("#extension-page-container").hide();
|
||||
$("#connection-page").show();
|
||||
|
||||
try {
|
||||
const extensionListContainer = document.getElementById('extension-list-container');
|
||||
const extensionListContainer = document.getElementById('extension-list');
|
||||
extensionListContainer.innerHTML = ''; // Clear previous entries
|
||||
const response = await client.listExtensions(new extension.Empty(), {});
|
||||
const header = document.createElement('h1');
|
||||
header.classList.add('mb-4');
|
||||
header.textContent = "Extension List";
|
||||
extensionListContainer.appendChild(header);
|
||||
|
||||
const response = await extensionClient.listExtensions(new extension.Empty(), {});
|
||||
|
||||
const extensionList = response.getExtensionsList();
|
||||
extensionList.forEach(ext => {
|
||||
const listItem = createExtensionListItem(ext);
|
||||
@@ -38,14 +36,20 @@ function createExtensionListItem(ext) {
|
||||
descriptionElement.className = 'mb-0';
|
||||
descriptionElement.textContent = ext.getDescription();
|
||||
contentDiv.appendChild(descriptionElement);
|
||||
|
||||
contentDiv.style.width="100%";
|
||||
listItem.appendChild(contentDiv);
|
||||
|
||||
const switchDiv = createSwitchElement(ext);
|
||||
listItem.appendChild(switchDiv);
|
||||
const {openExtensionPage} = require('./extensionPage.js');
|
||||
|
||||
listItem.addEventListener('click', () => openExtensionPage(ext.getId()));
|
||||
contentDiv.addEventListener('click', () =>{
|
||||
if (!ext.getEnable() ){
|
||||
alert("Extension is not enabled")
|
||||
return
|
||||
}
|
||||
openExtensionPage(ext.getId())
|
||||
});
|
||||
|
||||
return listItem;
|
||||
}
|
||||
@@ -58,7 +62,10 @@ function createSwitchElement(ext) {
|
||||
switchButton.type = 'checkbox';
|
||||
switchButton.className = 'form-check-input';
|
||||
switchButton.checked = ext.getEnable();
|
||||
switchButton.addEventListener('change', () => toggleExtension(ext.getId(), switchButton.checked));
|
||||
switchButton.addEventListener('change', (e) => {
|
||||
|
||||
toggleExtension(ext.getId(), switchButton.checked)
|
||||
});
|
||||
|
||||
switchDiv.appendChild(switchButton);
|
||||
return switchDiv;
|
||||
@@ -70,11 +77,12 @@ async function toggleExtension(extensionId, enable) {
|
||||
request.setEnable(enable);
|
||||
|
||||
try {
|
||||
await client.editExtension(request, {});
|
||||
await extensionClient.editExtension(request, {});
|
||||
console.log(`Extension ${extensionId} updated to ${enable ? 'enabled' : 'disabled'}`);
|
||||
} catch (err) {
|
||||
console.error('Error updating extension status:', err);
|
||||
}
|
||||
listExtensions();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
const { client,extension } = require('./client.js');
|
||||
const { extensionClient } = require('./client.js');
|
||||
const extension = require("./extension_grpc_web_pb.js");
|
||||
|
||||
const { renderForm } = require('./formRenderer.js');
|
||||
const { listExtensions } = require('./extensionList.js');
|
||||
var currentExtensionId=undefined;
|
||||
function openExtensionPage(extensionId) {
|
||||
currentExtensionId=extensionId;
|
||||
$("#extension-list-container").hide();
|
||||
$("#extension-page-container").show();
|
||||
const request = new extension.ExtensionRequest();
|
||||
request.setExtensionId(extensionId);
|
||||
$("#extension-page-container").show();
|
||||
$("#connection-page").hide();
|
||||
connect()
|
||||
}
|
||||
|
||||
const stream = client.connect(request, {});
|
||||
function connect() {
|
||||
const request = new extension.ExtensionRequest();
|
||||
request.setExtensionId(currentExtensionId);
|
||||
|
||||
const stream = extensionClient.connect(request, {});
|
||||
|
||||
stream.on('data', (response) => {
|
||||
|
||||
console.log('Receving ',response);
|
||||
if (response.getExtensionId() === currentExtensionId) {
|
||||
ui=JSON.parse(response.getJsonUi())
|
||||
if(response.getType()== proto.hiddifyrpc.ExtensionResponseType.SHOW_DIALOG) {
|
||||
@@ -27,25 +34,29 @@ function openExtensionPage(extensionId) {
|
||||
|
||||
stream.on('error', (err) => {
|
||||
console.error('Error opening extension page:', err);
|
||||
// openExtensionPage(extensionId);
|
||||
});
|
||||
|
||||
stream.on('end', () => {
|
||||
console.log('Stream ended');
|
||||
setTimeout(connect, 1000);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
async function handleSubmitButtonClick(event) {
|
||||
event.preventDefault();
|
||||
bootstrap.Modal.getOrCreateInstance("#extension-dialog").hide();
|
||||
const formData = new FormData(event.target.closest('form'));
|
||||
const request = new extension.ExtensionRequest();
|
||||
|
||||
const datamap=request.getDataMap()
|
||||
formData.forEach((value, key) => {
|
||||
request.getDataMap()[key] = value;
|
||||
datamap.set(key,value);
|
||||
});
|
||||
request.setExtensionId(currentExtensionId);
|
||||
|
||||
try {
|
||||
await client.submitForm(request, {});
|
||||
await extensionClient.submitForm(request, {});
|
||||
console.log('Form submitted successfully.');
|
||||
} catch (err) {
|
||||
console.error('Error submitting form:', err);
|
||||
@@ -58,7 +69,9 @@ async function handleCancelButtonClick(event) {
|
||||
request.setExtensionId(currentExtensionId);
|
||||
|
||||
try {
|
||||
await client.cancel(request, {});
|
||||
bootstrap.Modal.getOrCreateInstance("#extension-dialog").hide();
|
||||
|
||||
await extensionClient.cancel(request, {});
|
||||
console.log('Extension cancelled successfully.');
|
||||
} catch (err) {
|
||||
console.error('Error cancelling extension:', err);
|
||||
@@ -71,7 +84,7 @@ async function handleStopButtonClick(event) {
|
||||
request.setExtensionId(currentExtensionId);
|
||||
|
||||
try {
|
||||
await client.stop(request, {});
|
||||
await extensionClient.stop(request, {});
|
||||
console.log('Extension stopped successfully.');
|
||||
currentExtensionId = undefined;
|
||||
listExtensions(); // Return to the extension list
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
const { client } = require('./client.js');
|
||||
const extension = require("./extension_grpc_web_pb.js");
|
||||
|
||||
const ansi_up = new AnsiUp({
|
||||
escape_html: false,
|
||||
|
||||
});
|
||||
|
||||
|
||||
function renderForm(json, dialog, submitAction, cancelAction, stopAction) {
|
||||
const container = document.getElementById(`extension-page-container${dialog}`);
|
||||
@@ -10,23 +14,36 @@ function renderForm(json, dialog, submitAction, cancelAction, stopAction) {
|
||||
existingForm.remove();
|
||||
}
|
||||
const form = document.createElement('form');
|
||||
container.appendChild(form);
|
||||
form.id = formId;
|
||||
|
||||
if (dialog === "dialog") {
|
||||
document.getElementById("modalLabel").textContent = json.title;
|
||||
} else {
|
||||
const titleElement = createTitleElement(json);
|
||||
if (stopAction != undefined) {
|
||||
const stopButton = document.createElement('button');
|
||||
stopButton.textContent = "Back";
|
||||
stopButton.classList.add('btn', 'btn-danger');
|
||||
stopButton.addEventListener('click', stopAction);
|
||||
form.appendChild(stopButton);
|
||||
}
|
||||
form.appendChild(titleElement);
|
||||
}
|
||||
addElementsToForm(form, json);
|
||||
const buttonGroup = createButtonGroup(json, submitAction, cancelAction, stopAction);
|
||||
const buttonGroup = createButtonGroup(json, submitAction, cancelAction);
|
||||
if (dialog === "dialog") {
|
||||
document.getElementById("modal-footer").innerHTML = '';
|
||||
document.getElementById("modal-footer").appendChild(buttonGroup);
|
||||
const dialog = bootstrap.Modal.getOrCreateInstance("#extension-dialog");
|
||||
dialog.show()
|
||||
dialog.on("hidden.bs.modal", () => {
|
||||
cancelAction()
|
||||
})
|
||||
} else {
|
||||
form.appendChild(buttonGroup);
|
||||
}
|
||||
container.appendChild(form);
|
||||
|
||||
}
|
||||
|
||||
function addElementsToForm(form, json) {
|
||||
@@ -36,12 +53,12 @@ function addElementsToForm(form, json) {
|
||||
const description = document.createElement('p');
|
||||
description.textContent = json.description;
|
||||
form.appendChild(description);
|
||||
|
||||
json.fields.forEach(field => {
|
||||
const formGroup = createFormGroup(field);
|
||||
form.appendChild(formGroup);
|
||||
});
|
||||
|
||||
if (json.fields) {
|
||||
json.fields.forEach(field => {
|
||||
const formGroup = createFormGroup(field);
|
||||
form.appendChild(formGroup);
|
||||
});
|
||||
}
|
||||
|
||||
return form;
|
||||
}
|
||||
@@ -72,6 +89,11 @@ function createInputElement(field) {
|
||||
let input;
|
||||
|
||||
switch (field.type) {
|
||||
case "Console":
|
||||
input = document.createElement('pre');
|
||||
input.innerHTML = ansi_up.ansi_to_html(field.value || field.placeholder || '');
|
||||
input.style.maxHeight = field.lines * 20 + 'px';
|
||||
break;
|
||||
case "TextArea":
|
||||
input = document.createElement('textarea');
|
||||
input.rows = field.lines || 3;
|
||||
@@ -167,30 +189,25 @@ function createSwitchElement(field) {
|
||||
return switchWrapper;
|
||||
}
|
||||
|
||||
function createButtonGroup(json, submitAction, cancelAction, stopAction) {
|
||||
function createButtonGroup(json, submitAction, cancelAction) {
|
||||
const buttonGroup = document.createElement('div');
|
||||
buttonGroup.classList.add('btn-group');
|
||||
json.buttons.forEach(buttonText => {
|
||||
const btn = document.createElement('button');
|
||||
btn.classList.add('btn',"btn-default");
|
||||
buttonGroup.appendChild(btn);
|
||||
btn.textContent = buttonText
|
||||
if (buttonText=="Cancel") {
|
||||
btn.classList.add( 'btn-secondary');
|
||||
btn.addEventListener('click', cancelAction);
|
||||
}else{
|
||||
if (buttonText=="Submit"||buttonText=="Ok")
|
||||
btn.classList.add('btn-primary');
|
||||
btn.addEventListener('click', submitAction);
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
const cancelButton = document.createElement('button');
|
||||
cancelButton.textContent = "Cancel";
|
||||
cancelButton.classList.add('btn', 'btn-secondary');
|
||||
cancelButton.addEventListener('click', cancelAction);
|
||||
buttonGroup.appendChild(cancelButton);
|
||||
if (stopAction != undefined) {
|
||||
const stopButton = document.createElement('button');
|
||||
stopButton.textContent = "Stop";
|
||||
stopButton.classList.add('btn', 'btn-danger');
|
||||
stopButton.addEventListener('click', stopAction);
|
||||
buttonGroup.appendChild(stopButton);
|
||||
}
|
||||
|
||||
if (json.buttonMode === "SubmitCancel") {
|
||||
const submitButton = document.createElement('button');
|
||||
submitButton.textContent = "Submit";
|
||||
submitButton.classList.add('btn', 'btn-primary');
|
||||
submitButton.addEventListener('click', submitAction);
|
||||
buttonGroup.appendChild(submitButton);
|
||||
}
|
||||
|
||||
|
||||
return buttonGroup;
|
||||
|
||||
@@ -250,6 +250,230 @@ proto.hiddifyrpc.CorePromiseClient.prototype.start =
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {!grpc.web.MethodDescriptor<
|
||||
* !proto.hiddifyrpc.Empty,
|
||||
* !proto.hiddifyrpc.CoreInfoResponse>}
|
||||
*/
|
||||
const methodDescriptor_Core_CoreInfoListener = new grpc.web.MethodDescriptor(
|
||||
'/hiddifyrpc.Core/CoreInfoListener',
|
||||
grpc.web.MethodType.SERVER_STREAMING,
|
||||
base_pb.Empty,
|
||||
proto.hiddifyrpc.CoreInfoResponse,
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
function(request) {
|
||||
return request.serializeBinary();
|
||||
},
|
||||
proto.hiddifyrpc.CoreInfoResponse.deserializeBinary
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.CoreInfoResponse>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CoreClient.prototype.coreInfoListener =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/CoreInfoListener',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_CoreInfoListener);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.CoreInfoResponse>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CorePromiseClient.prototype.coreInfoListener =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/CoreInfoListener',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_CoreInfoListener);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {!grpc.web.MethodDescriptor<
|
||||
* !proto.hiddifyrpc.Empty,
|
||||
* !proto.hiddifyrpc.OutboundGroupList>}
|
||||
*/
|
||||
const methodDescriptor_Core_OutboundsInfo = new grpc.web.MethodDescriptor(
|
||||
'/hiddifyrpc.Core/OutboundsInfo',
|
||||
grpc.web.MethodType.SERVER_STREAMING,
|
||||
base_pb.Empty,
|
||||
proto.hiddifyrpc.OutboundGroupList,
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
function(request) {
|
||||
return request.serializeBinary();
|
||||
},
|
||||
proto.hiddifyrpc.OutboundGroupList.deserializeBinary
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.OutboundGroupList>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CoreClient.prototype.outboundsInfo =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/OutboundsInfo',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_OutboundsInfo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.OutboundGroupList>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CorePromiseClient.prototype.outboundsInfo =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/OutboundsInfo',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_OutboundsInfo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {!grpc.web.MethodDescriptor<
|
||||
* !proto.hiddifyrpc.Empty,
|
||||
* !proto.hiddifyrpc.OutboundGroupList>}
|
||||
*/
|
||||
const methodDescriptor_Core_MainOutboundsInfo = new grpc.web.MethodDescriptor(
|
||||
'/hiddifyrpc.Core/MainOutboundsInfo',
|
||||
grpc.web.MethodType.SERVER_STREAMING,
|
||||
base_pb.Empty,
|
||||
proto.hiddifyrpc.OutboundGroupList,
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
function(request) {
|
||||
return request.serializeBinary();
|
||||
},
|
||||
proto.hiddifyrpc.OutboundGroupList.deserializeBinary
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.OutboundGroupList>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CoreClient.prototype.mainOutboundsInfo =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/MainOutboundsInfo',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_MainOutboundsInfo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.OutboundGroupList>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CorePromiseClient.prototype.mainOutboundsInfo =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/MainOutboundsInfo',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_MainOutboundsInfo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {!grpc.web.MethodDescriptor<
|
||||
* !proto.hiddifyrpc.Empty,
|
||||
* !proto.hiddifyrpc.SystemInfo>}
|
||||
*/
|
||||
const methodDescriptor_Core_GetSystemInfo = new grpc.web.MethodDescriptor(
|
||||
'/hiddifyrpc.Core/GetSystemInfo',
|
||||
grpc.web.MethodType.SERVER_STREAMING,
|
||||
base_pb.Empty,
|
||||
proto.hiddifyrpc.SystemInfo,
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
function(request) {
|
||||
return request.serializeBinary();
|
||||
},
|
||||
proto.hiddifyrpc.SystemInfo.deserializeBinary
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.SystemInfo>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CoreClient.prototype.getSystemInfo =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/GetSystemInfo',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_GetSystemInfo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.SystemInfo>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CorePromiseClient.prototype.getSystemInfo =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/GetSystemInfo',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_GetSystemInfo);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {!grpc.web.MethodDescriptor<
|
||||
@@ -375,16 +599,16 @@ proto.hiddifyrpc.CorePromiseClient.prototype.parse =
|
||||
/**
|
||||
* @const
|
||||
* @type {!grpc.web.MethodDescriptor<
|
||||
* !proto.hiddifyrpc.ChangeConfigOptionsRequest,
|
||||
* !proto.hiddifyrpc.ChangeHiddifySettingsRequest,
|
||||
* !proto.hiddifyrpc.CoreInfoResponse>}
|
||||
*/
|
||||
const methodDescriptor_Core_ChangeConfigOptions = new grpc.web.MethodDescriptor(
|
||||
'/hiddifyrpc.Core/ChangeConfigOptions',
|
||||
const methodDescriptor_Core_ChangeHiddifySettings = new grpc.web.MethodDescriptor(
|
||||
'/hiddifyrpc.Core/ChangeHiddifySettings',
|
||||
grpc.web.MethodType.UNARY,
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest,
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest,
|
||||
proto.hiddifyrpc.CoreInfoResponse,
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.ChangeConfigOptionsRequest} request
|
||||
* @param {!proto.hiddifyrpc.ChangeHiddifySettingsRequest} request
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
function(request) {
|
||||
@@ -395,7 +619,7 @@ const methodDescriptor_Core_ChangeConfigOptions = new grpc.web.MethodDescriptor(
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.ChangeConfigOptionsRequest} request The
|
||||
* @param {!proto.hiddifyrpc.ChangeHiddifySettingsRequest} request The
|
||||
* request proto
|
||||
* @param {?Object<string, string>} metadata User defined
|
||||
* call metadata
|
||||
@@ -404,32 +628,32 @@ const methodDescriptor_Core_ChangeConfigOptions = new grpc.web.MethodDescriptor(
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.CoreInfoResponse>|undefined}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CoreClient.prototype.changeConfigOptions =
|
||||
proto.hiddifyrpc.CoreClient.prototype.changeHiddifySettings =
|
||||
function(request, metadata, callback) {
|
||||
return this.client_.rpcCall(this.hostname_ +
|
||||
'/hiddifyrpc.Core/ChangeConfigOptions',
|
||||
'/hiddifyrpc.Core/ChangeHiddifySettings',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_ChangeConfigOptions,
|
||||
methodDescriptor_Core_ChangeHiddifySettings,
|
||||
callback);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.ChangeConfigOptionsRequest} request The
|
||||
* @param {!proto.hiddifyrpc.ChangeHiddifySettingsRequest} request The
|
||||
* request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!Promise<!proto.hiddifyrpc.CoreInfoResponse>}
|
||||
* Promise that resolves to the response
|
||||
*/
|
||||
proto.hiddifyrpc.CorePromiseClient.prototype.changeConfigOptions =
|
||||
proto.hiddifyrpc.CorePromiseClient.prototype.changeHiddifySettings =
|
||||
function(request, metadata) {
|
||||
return this.client_.unaryCall(this.hostname_ +
|
||||
'/hiddifyrpc.Core/ChangeConfigOptions',
|
||||
'/hiddifyrpc.Core/ChangeHiddifySettings',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_ChangeConfigOptions);
|
||||
methodDescriptor_Core_ChangeHiddifySettings);
|
||||
};
|
||||
|
||||
|
||||
@@ -921,6 +1145,62 @@ proto.hiddifyrpc.CorePromiseClient.prototype.setSystemProxyEnabled =
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @type {!grpc.web.MethodDescriptor<
|
||||
* !proto.hiddifyrpc.Empty,
|
||||
* !proto.hiddifyrpc.LogMessage>}
|
||||
*/
|
||||
const methodDescriptor_Core_LogListener = new grpc.web.MethodDescriptor(
|
||||
'/hiddifyrpc.Core/LogListener',
|
||||
grpc.web.MethodType.SERVER_STREAMING,
|
||||
base_pb.Empty,
|
||||
proto.hiddifyrpc.LogMessage,
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
function(request) {
|
||||
return request.serializeBinary();
|
||||
},
|
||||
proto.hiddifyrpc.LogMessage.deserializeBinary
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.LogMessage>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CoreClient.prototype.logListener =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/LogListener',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_LogListener);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {!proto.hiddifyrpc.Empty} request The request proto
|
||||
* @param {?Object<string, string>=} metadata User defined
|
||||
* call metadata
|
||||
* @return {!grpc.web.ClientReadableStream<!proto.hiddifyrpc.LogMessage>}
|
||||
* The XHR Node Readable Stream
|
||||
*/
|
||||
proto.hiddifyrpc.CorePromiseClient.prototype.logListener =
|
||||
function(request, metadata) {
|
||||
return this.client_.serverStreaming(this.hostname_ +
|
||||
'/hiddifyrpc.Core/LogListener',
|
||||
request,
|
||||
metadata || {},
|
||||
methodDescriptor_Core_LogListener);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} hostname
|
||||
* @param {?Object} credentials
|
||||
|
||||
@@ -23,7 +23,7 @@ var global =
|
||||
|
||||
var base_pb = require('./base_pb.js');
|
||||
goog.object.extend(proto, base_pb);
|
||||
goog.exportSymbol('proto.hiddifyrpc.ChangeConfigOptionsRequest', null, global);
|
||||
goog.exportSymbol('proto.hiddifyrpc.ChangeHiddifySettingsRequest', null, global);
|
||||
goog.exportSymbol('proto.hiddifyrpc.CoreInfoResponse', null, global);
|
||||
goog.exportSymbol('proto.hiddifyrpc.CoreState', null, global);
|
||||
goog.exportSymbol('proto.hiddifyrpc.GenerateConfigRequest', null, global);
|
||||
@@ -356,16 +356,16 @@ if (goog.DEBUG && !COMPILED) {
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest = function(opt_data) {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.hiddifyrpc.ChangeConfigOptionsRequest, jspb.Message);
|
||||
goog.inherits(proto.hiddifyrpc.ChangeHiddifySettingsRequest, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.displayName = 'proto.hiddifyrpc.ChangeConfigOptionsRequest';
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.displayName = 'proto.hiddifyrpc.ChangeHiddifySettingsRequest';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
@@ -3625,8 +3625,8 @@ if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.hiddifyrpc.ChangeConfigOptionsRequest.toObject(opt_includeInstance, this);
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.hiddifyrpc.ChangeHiddifySettingsRequest.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
@@ -3635,13 +3635,13 @@ proto.hiddifyrpc.ChangeConfigOptionsRequest.prototype.toObject = function(opt_in
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.hiddifyrpc.ChangeConfigOptionsRequest} msg The msg instance to transform.
|
||||
* @param {!proto.hiddifyrpc.ChangeHiddifySettingsRequest} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.toObject = function(includeInstance, msg) {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
configOptionsJson: jspb.Message.getFieldWithDefault(msg, 1, "")
|
||||
hiddifySettingsJson: jspb.Message.getFieldWithDefault(msg, 1, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@@ -3655,23 +3655,23 @@ configOptionsJson: jspb.Message.getFieldWithDefault(msg, 1, "")
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.hiddifyrpc.ChangeConfigOptionsRequest}
|
||||
* @return {!proto.hiddifyrpc.ChangeHiddifySettingsRequest}
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.deserializeBinary = function(bytes) {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.hiddifyrpc.ChangeConfigOptionsRequest;
|
||||
return proto.hiddifyrpc.ChangeConfigOptionsRequest.deserializeBinaryFromReader(msg, reader);
|
||||
var msg = new proto.hiddifyrpc.ChangeHiddifySettingsRequest;
|
||||
return proto.hiddifyrpc.ChangeHiddifySettingsRequest.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.hiddifyrpc.ChangeConfigOptionsRequest} msg The message object to deserialize into.
|
||||
* @param {!proto.hiddifyrpc.ChangeHiddifySettingsRequest} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.hiddifyrpc.ChangeConfigOptionsRequest}
|
||||
* @return {!proto.hiddifyrpc.ChangeHiddifySettingsRequest}
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.deserializeBinaryFromReader = function(msg, reader) {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
@@ -3680,7 +3680,7 @@ proto.hiddifyrpc.ChangeConfigOptionsRequest.deserializeBinaryFromReader = functi
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setConfigOptionsJson(value);
|
||||
msg.setHiddifySettingsJson(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
@@ -3695,9 +3695,9 @@ proto.hiddifyrpc.ChangeConfigOptionsRequest.deserializeBinaryFromReader = functi
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.prototype.serializeBinary = function() {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.serializeBinaryToWriter(this, writer);
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
@@ -3705,13 +3705,13 @@ proto.hiddifyrpc.ChangeConfigOptionsRequest.prototype.serializeBinary = function
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.hiddifyrpc.ChangeConfigOptionsRequest} message
|
||||
* @param {!proto.hiddifyrpc.ChangeHiddifySettingsRequest} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.serializeBinaryToWriter = function(message, writer) {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getConfigOptionsJson();
|
||||
f = message.getHiddifySettingsJson();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
1,
|
||||
@@ -3722,19 +3722,19 @@ proto.hiddifyrpc.ChangeConfigOptionsRequest.serializeBinaryToWriter = function(m
|
||||
|
||||
|
||||
/**
|
||||
* optional string config_options_json = 1;
|
||||
* optional string hiddify_settings_json = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.prototype.getConfigOptionsJson = function() {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.prototype.getHiddifySettingsJson = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.hiddifyrpc.ChangeConfigOptionsRequest} returns this
|
||||
* @return {!proto.hiddifyrpc.ChangeHiddifySettingsRequest} returns this
|
||||
*/
|
||||
proto.hiddifyrpc.ChangeConfigOptionsRequest.prototype.setConfigOptionsJson = function(value) {
|
||||
proto.hiddifyrpc.ChangeHiddifySettingsRequest.prototype.setHiddifySettingsJson = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
45
extension/interface.go
Normal file
45
extension/interface.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package extension
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hiddify/hiddify-core/common"
|
||||
)
|
||||
|
||||
var (
|
||||
allExtensionsMap = make(map[string]ExtensionFactory)
|
||||
enabledExtensionsMap = make(map[string]*Extension)
|
||||
generalExtensionData = mustSaveExtensionData{
|
||||
ExtensionStatusMap: make(map[string]bool),
|
||||
}
|
||||
)
|
||||
|
||||
type mustSaveExtensionData struct {
|
||||
ExtensionStatusMap map[string]bool `json:"extensionStatusMap"`
|
||||
}
|
||||
|
||||
func RegisterExtension(factory ExtensionFactory) error {
|
||||
if _, ok := allExtensionsMap[factory.Id]; ok {
|
||||
err := fmt.Errorf("Extension with ID %s already exists", factory.Id)
|
||||
log.Fatal(err)
|
||||
return err
|
||||
}
|
||||
allExtensionsMap[factory.Id] = factory
|
||||
common.Storage.GetExtensionData("default", &generalExtensionData)
|
||||
|
||||
if val, ok := generalExtensionData.ExtensionStatusMap[factory.Id]; ok && val {
|
||||
loadExtension(factory)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadExtension(factory ExtensionFactory) error {
|
||||
extension := factory.Builder()
|
||||
extension.init(factory.Id)
|
||||
|
||||
// fmt.Printf("Registered extension: %+v\n", extension)
|
||||
enabledExtensionsMap[factory.Id] = &extension
|
||||
|
||||
return nil
|
||||
}
|
||||
47
extension/sdk/interface.go
Normal file
47
extension/sdk/interface.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/hiddify/hiddify-core/config"
|
||||
v2 "github.com/hiddify/hiddify-core/v2"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
func RunInstance(hiddifySettings *config.HiddifyOptions, singconfig *option.Options) (*v2.HiddifyService, error) {
|
||||
return v2.RunInstance(hiddifySettings, singconfig)
|
||||
}
|
||||
|
||||
func ParseConfig(hiddifySettings *config.HiddifyOptions, configStr string) (*option.Options, error) {
|
||||
if hiddifySettings == nil {
|
||||
hiddifySettings = config.DefaultHiddifyOptions()
|
||||
}
|
||||
if strings.HasPrefix(configStr, "http://") || strings.HasPrefix(configStr, "https://") {
|
||||
client := &http.Client{}
|
||||
configPath := strings.Split(configStr, "\n")[0]
|
||||
// Create a new request
|
||||
req, err := http.NewRequest("GET", configPath, nil)
|
||||
if err != nil {
|
||||
fmt.Println("Error creating request:", err)
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("User-Agent", "HiddifyNext/2.3.1 ("+runtime.GOOS+") like ClashMeta v2ray sing-box")
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error making GET request:", err)
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read config body: %w", err)
|
||||
}
|
||||
configStr = string(body)
|
||||
}
|
||||
return config.ParseConfigContentToOptions(configStr, true, hiddifySettings, false)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package ui_elements
|
||||
package ui
|
||||
|
||||
// // Field is an interface that all specific field types implement.
|
||||
// type Field interface {
|
||||
@@ -1,4 +1,4 @@
|
||||
package ui_elements
|
||||
package ui
|
||||
|
||||
// import (
|
||||
// "encoding/json"
|
||||
@@ -1,4 +1,4 @@
|
||||
package ui_elements
|
||||
package ui
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@@ -20,27 +20,27 @@ const (
|
||||
FieldSwitch string = "Switch"
|
||||
FieldCheckbox string = "Checkbox"
|
||||
FieldRadioButton string = "RadioButton"
|
||||
FieldConsole string = "Console"
|
||||
ValidatorDigitsOnly string = "digitsOnly"
|
||||
Button_SubmitCancel string = "SubmitCancel"
|
||||
Button_Cancel string = "Cancel"
|
||||
|
||||
Button_Ok string = "Ok"
|
||||
Button_Submit string = "Submit"
|
||||
Button_Cancel string = "Cancel"
|
||||
)
|
||||
|
||||
// FormField extends GenericField with additional common properties.
|
||||
type FormField struct {
|
||||
Key string `json:"key"`
|
||||
Type string `json:"type"`
|
||||
Label string `json:"label,omitempty"`
|
||||
LabelHidden bool `json:"labelHidden"`
|
||||
Required bool `json:"required,omitempty"`
|
||||
Placeholder string `json:"placeholder,omitempty"`
|
||||
Readonly bool `json:"readonly,omitempty"`
|
||||
Value string `json:"value"`
|
||||
Validator string `json:"validator,omitempty"`
|
||||
Items []SelectItem `json:"items,omitempty"`
|
||||
Lines int `json:"lines,omitempty"`
|
||||
VerticalScroll bool `json:"verticalScroll,omitempty"`
|
||||
HorizontalScroll bool `json:"horizontalScroll,omitempty"`
|
||||
Monospace bool `json:"monospace,omitempty"`
|
||||
Key string `json:"key"`
|
||||
Type string `json:"type"`
|
||||
Label string `json:"label,omitempty"`
|
||||
LabelHidden bool `json:"labelHidden"`
|
||||
Required bool `json:"required,omitempty"`
|
||||
Placeholder string `json:"placeholder,omitempty"`
|
||||
Readonly bool `json:"readonly,omitempty"`
|
||||
Value string `json:"value"`
|
||||
Validator string `json:"validator,omitempty"`
|
||||
Items []SelectItem `json:"items,omitempty"`
|
||||
Lines int `json:"lines,omitempty"`
|
||||
}
|
||||
|
||||
// GetType returns the type of the field.
|
||||
@@ -62,7 +62,7 @@ type Form struct {
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Fields []FormField `json:"fields"`
|
||||
ButtonMode string `json:"buttonMode"`
|
||||
Buttons []string `json:"buttons"`
|
||||
}
|
||||
|
||||
func (f *Form) ToJSON() string {
|
||||
@@ -1,4 +1,4 @@
|
||||
package ui_elements
|
||||
package ui
|
||||
|
||||
// // ContentField represents a label with additional properties.
|
||||
// type ContentField struct {
|
||||
1
extension/ui/data.go
Normal file
1
extension/ui/data.go
Normal file
@@ -0,0 +1 @@
|
||||
package ui
|
||||
@@ -1,4 +1,4 @@
|
||||
package ui_elements
|
||||
package ui
|
||||
|
||||
// import (
|
||||
// "encoding/json"
|
||||
Reference in New Issue
Block a user