mirror of
https://github.com/v2fly/v2ray-core.git
synced 2026-01-02 23:35:40 -05:00
Add Persistent Storage Support to V2Ray (#3300)
* update protogen to strip unused part * add persistent storage support * fix coding style * update linter setting * update github integration
This commit is contained in:
committed by
GitHub
parent
3ee9045697
commit
78cd513b82
6
.github/linters/.golangci.yml
vendored
6
.github/linters/.golangci.yml
vendored
@@ -1,8 +1,5 @@
|
|||||||
run:
|
run:
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
skip-files:
|
|
||||||
- generated.*
|
|
||||||
- .pb.go
|
|
||||||
|
|
||||||
issues:
|
issues:
|
||||||
new: true
|
new: true
|
||||||
@@ -13,6 +10,9 @@ issues:
|
|||||||
- linters:
|
- linters:
|
||||||
- stylecheck
|
- stylecheck
|
||||||
text: "ST1016:"
|
text: "ST1016:"
|
||||||
|
exclude-files:
|
||||||
|
- generated.*
|
||||||
|
- .pb.go
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
|
|||||||
2
.github/workflows/deb.yml
vendored
2
.github/workflows/deb.yml
vendored
@@ -53,7 +53,7 @@ jobs:
|
|||||||
cp ../*.deb ./
|
cp ../*.deb ./
|
||||||
|
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: v2ray-debian-packages
|
name: v2ray-debian-packages
|
||||||
path: ./*.deb
|
path: ./*.deb
|
||||||
|
|||||||
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -188,7 +188,7 @@ jobs:
|
|||||||
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
|
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
|
||||||
|
|
||||||
- name: Upload ZIP file to Artifacts
|
- name: Upload ZIP file to Artifacts
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
|
name: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
|
||||||
path: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
|
path: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
|
||||||
@@ -217,7 +217,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ^1.23
|
go-version: ^1.23
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: build_artifacts
|
path: build_artifacts
|
||||||
|
|
||||||
@@ -252,17 +252,17 @@ jobs:
|
|||||||
openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST
|
openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST
|
||||||
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
|
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Release.unsigned
|
name: Release.unsigned
|
||||||
path: build_artifacts/Release.unsigned
|
path: build_artifacts/Release.unsigned
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Release.unsigned.dgst
|
name: Release.unsigned.dgst
|
||||||
path: build_artifacts/Release.unsigned.dgst
|
path: build_artifacts/Release.unsigned.dgst
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: v2ray-extra.zip
|
name: v2ray-extra.zip
|
||||||
path: build_artifacts/v2ray-extra.zip
|
path: build_artifacts/v2ray-extra.zip
|
||||||
|
|||||||
@@ -365,11 +365,12 @@ func (x *Intensity) GetProbeInterval() uint32 {
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
// @Document The selectors for outbound under observation
|
// @Document The selectors for outbound under observation
|
||||||
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
|
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
|
||||||
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
|
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
|
||||||
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
PersistentProbeResult bool `protobuf:"varint,5,opt,name=persistent_probe_result,json=persistentProbeResult,proto3" json:"persistent_probe_result,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
func (x *Config) Reset() {
|
||||||
@@ -423,6 +424,13 @@ func (x *Config) GetProbeInterval() int64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetPersistentProbeResult() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.PersistentProbeResult
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
var File_app_observatory_config_proto protoreflect.FileDescriptor
|
var File_app_observatory_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_app_observatory_config_proto_rawDesc = string([]byte{
|
var file_app_observatory_config_proto_rawDesc = string([]byte{
|
||||||
@@ -476,24 +484,28 @@ var file_app_observatory_config_proto_rawDesc = string([]byte{
|
|||||||
0x22, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a,
|
0x22, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a,
|
||||||
0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
|
0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65,
|
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65,
|
||||||
0x72, 0x76, 0x61, 0x6c, 0x22, 0x9d, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
0x72, 0x76, 0x61, 0x6c, 0x22, 0xd5, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
|
||||||
0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
|
0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
|
||||||
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
|
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
|
||||||
0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72,
|
0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72,
|
||||||
0x6f, 0x62, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
|
0x6f, 0x62, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
|
||||||
0x72, 0x6f, 0x62, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65,
|
0x72, 0x6f, 0x62, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65,
|
||||||
0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
|
0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||||
0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x3a, 0x24,
|
0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x36,
|
||||||
0x82, 0xb5, 0x18, 0x20, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x15, 0x62,
|
0x0a, 0x17, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f,
|
||||||
0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
|
0x62, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
0x74, 0x6f, 0x72, 0x79, 0x42, 0x6f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61,
|
0x15, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x62, 0x65,
|
||||||
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72,
|
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3a, 0x24, 0x82, 0xb5, 0x18, 0x20, 0x0a, 0x07, 0x73, 0x65,
|
||||||
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
|
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x15, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e,
|
||||||
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79,
|
0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x6f, 0x0a, 0x1e,
|
||||||
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73,
|
0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
|
||||||
0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79,
|
0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01,
|
||||||
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76,
|
0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66,
|
||||||
0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35,
|
||||||
|
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79,
|
||||||
|
0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70,
|
||||||
|
0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70,
|
||||||
|
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
})
|
})
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -84,4 +84,6 @@ message Config {
|
|||||||
string probe_url = 3;
|
string probe_url = 3;
|
||||||
|
|
||||||
int64 probe_interval = 4;
|
int64 probe_interval = 4;
|
||||||
|
|
||||||
|
bool persistent_probe_result = 5;
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,11 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/app/persistentstorage"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/app/persistentstorage/protostorage"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
|
||||||
core "github.com/v2fly/v2ray-core/v5"
|
core "github.com/v2fly/v2ray-core/v5"
|
||||||
@@ -34,7 +39,10 @@ type Observer struct {
|
|||||||
|
|
||||||
finished *done.Instance
|
finished *done.Instance
|
||||||
|
|
||||||
ohm outbound.Manager
|
ohm outbound.Manager
|
||||||
|
persistStorage persistentstorage.ScopedPersistentStorage
|
||||||
|
|
||||||
|
persistOutboundStatusProtoStorage protostorage.ProtoPersistentStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
|
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
|
||||||
@@ -47,6 +55,24 @@ func (o *Observer) Type() interface{} {
|
|||||||
|
|
||||||
func (o *Observer) Start() error {
|
func (o *Observer) Start() error {
|
||||||
if o.config != nil && len(o.config.SubjectSelector) != 0 {
|
if o.config != nil && len(o.config.SubjectSelector) != 0 {
|
||||||
|
if o.config.PersistentProbeResult {
|
||||||
|
appEnvironment := envctx.EnvironmentFromContext(o.ctx).(environment.AppEnvironment)
|
||||||
|
o.persistStorage = appEnvironment.PersistentStorage()
|
||||||
|
|
||||||
|
outboundStatusStorage, err := o.persistStorage.NarrowScope(o.ctx, []byte("outbound_status"))
|
||||||
|
if err != nil {
|
||||||
|
return newError("failed to get persistent storage for outbound_status").Base(err)
|
||||||
|
}
|
||||||
|
o.persistOutboundStatusProtoStorage = outboundStatusStorage.(protostorage.ProtoPersistentStorage)
|
||||||
|
list, err := outboundStatusStorage.List(o.ctx, []byte(""))
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to list persisted outbound status").Base(err).WriteToLog()
|
||||||
|
} else {
|
||||||
|
for _, v := range list {
|
||||||
|
o.loadOutboundStatus(string(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
o.finished = done.New()
|
o.finished = done.New()
|
||||||
go o.background()
|
go o.background()
|
||||||
}
|
}
|
||||||
@@ -195,6 +221,12 @@ func (o *Observer) updateStatusForResult(outbound string, result *ProbeResult) {
|
|||||||
status.LastErrorReason = result.LastErrorReason
|
status.LastErrorReason = result.LastErrorReason
|
||||||
status.Delay = 99999999
|
status.Delay = 99999999
|
||||||
}
|
}
|
||||||
|
if o.config.PersistentProbeResult {
|
||||||
|
err := o.persistOutboundStatusProtoStorage.PutProto(o.ctx, outbound, status)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to persist outbound status").Base(err).WriteToLog()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
|
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
|
||||||
@@ -206,19 +238,33 @@ func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Observer) loadOutboundStatus(name string) {
|
||||||
|
if o.persistOutboundStatusProtoStorage == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
status := &OutboundStatus{}
|
||||||
|
err := o.persistOutboundStatusProtoStorage.GetProto(o.ctx, name, status)
|
||||||
|
if err != nil {
|
||||||
|
newError("failed to load outbound status").Base(err).WriteToLog()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
o.status = append(o.status, status)
|
||||||
|
}
|
||||||
|
|
||||||
func New(ctx context.Context, config *Config) (*Observer, error) {
|
func New(ctx context.Context, config *Config) (*Observer, error) {
|
||||||
var outboundManager outbound.Manager
|
obs := &Observer{
|
||||||
|
config: config,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
|
||||||
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
|
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
|
||||||
outboundManager = om
|
obs.ohm = om
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, newError("Cannot get depended features").Base(err)
|
return nil, newError("Cannot get depended features").Base(err)
|
||||||
}
|
}
|
||||||
return &Observer{
|
|
||||||
config: config,
|
return obs, nil
|
||||||
ctx: ctx,
|
|
||||||
ohm: outboundManager,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
214
app/persistentstorage/filesystemstorage/config.pb.go
Normal file
214
app/persistentstorage/filesystemstorage/config.pb.go
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package filesystemstorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/v2fly/v2ray-core/v5/common/protoext"
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type StateStorageRoot int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
StateStorageRoot_WorkDir StateStorageRoot = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for StateStorageRoot.
|
||||||
|
var (
|
||||||
|
StateStorageRoot_name = map[int32]string{
|
||||||
|
0: "WorkDir",
|
||||||
|
}
|
||||||
|
StateStorageRoot_value = map[string]int32{
|
||||||
|
"WorkDir": 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x StateStorageRoot) Enum() *StateStorageRoot {
|
||||||
|
p := new(StateStorageRoot)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x StateStorageRoot) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (StateStorageRoot) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_app_persistentstorage_filesystemstorage_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (StateStorageRoot) Type() protoreflect.EnumType {
|
||||||
|
return &file_app_persistentstorage_filesystemstorage_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x StateStorageRoot) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use StateStorageRoot.Descriptor instead.
|
||||||
|
func (StateStorageRoot) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_app_persistentstorage_filesystemstorage_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
StateStorageRoot StateStorageRoot `protobuf:"varint,1,opt,name=state_storage_root,json=stateStorageRoot,proto3,enum=v2ray.core.app.persistentstorage.filesystemstorage.StateStorageRoot" json:"state_storage_root,omitempty"`
|
||||||
|
InstanceName string `protobuf:"bytes,4,opt,name=instance_name,json=instanceName,proto3" json:"instance_name,omitempty"`
|
||||||
|
Protojson bool `protobuf:"varint,5,opt,name=protojson,proto3" json:"protojson,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) Reset() {
|
||||||
|
*x = Config{}
|
||||||
|
mi := &file_app_persistentstorage_filesystemstorage_config_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Config) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Config) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_app_persistentstorage_filesystemstorage_config_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Config) Descriptor() ([]byte, []int) {
|
||||||
|
return file_app_persistentstorage_filesystemstorage_config_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetStateStorageRoot() StateStorageRoot {
|
||||||
|
if x != nil {
|
||||||
|
return x.StateStorageRoot
|
||||||
|
}
|
||||||
|
return StateStorageRoot_WorkDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetInstanceName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.InstanceName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Config) GetProtojson() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Protojson
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_app_persistentstorage_filesystemstorage_config_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_app_persistentstorage_filesystemstorage_config_proto_rawDesc = string([]byte{
|
||||||
|
0x0a, 0x34, 0x61, 0x70, 0x70, 0x2f, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74,
|
||||||
|
0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74,
|
||||||
|
0x65, 0x6d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||||
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x32, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
|
||||||
|
0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e,
|
||||||
|
0x74, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73,
|
||||||
|
0x74, 0x65, 0x6d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x1a, 0x20, 0x63, 0x6f, 0x6d, 0x6d,
|
||||||
|
0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x65, 0x78, 0x74, 0x2f, 0x65, 0x78, 0x74, 0x65,
|
||||||
|
0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe1, 0x01, 0x0a,
|
||||||
|
0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x72, 0x0a, 0x12, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||||
|
0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x01, 0x20,
|
||||||
|
0x01, 0x28, 0x0e, 0x32, 0x44, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65,
|
||||||
|
0x2e, 0x61, 0x70, 0x70, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x73,
|
||||||
|
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65,
|
||||||
|
0x6d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74,
|
||||||
|
0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x52, 0x10, 0x73, 0x74, 0x61, 0x74, 0x65,
|
||||||
|
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x69,
|
||||||
|
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01,
|
||||||
|
0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65,
|
||||||
|
0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x05, 0x20,
|
||||||
|
0x01, 0x28, 0x08, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x20,
|
||||||
|
0x82, 0xb5, 0x18, 0x1c, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x11, 0x66,
|
||||||
|
0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
|
||||||
|
0x2a, 0x1f, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x74, 0x65, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
|
||||||
|
0x52, 0x6f, 0x6f, 0x74, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x6f, 0x72, 0x6b, 0x44, 0x69, 0x72, 0x10,
|
||||||
|
0x00, 0x42, 0xb3, 0x01, 0x0a, 0x32, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e,
|
||||||
|
0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x73,
|
||||||
|
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65,
|
||||||
|
0x6d, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x50, 0x01, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68,
|
||||||
|
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72,
|
||||||
|
0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x70,
|
||||||
|
0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65,
|
||||||
|
0x2f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x74, 0x6f, 0x72, 0x61,
|
||||||
|
0x67, 0x65, 0xaa, 0x02, 0x32, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e,
|
||||||
|
0x41, 0x70, 0x70, 0x2e, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x74,
|
||||||
|
0x6f, 0x72, 0x61, 0x67, 0x65, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d,
|
||||||
|
0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
})
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_app_persistentstorage_filesystemstorage_config_proto_rawDescOnce sync.Once
|
||||||
|
file_app_persistentstorage_filesystemstorage_config_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_app_persistentstorage_filesystemstorage_config_proto_rawDescGZIP() []byte {
|
||||||
|
file_app_persistentstorage_filesystemstorage_config_proto_rawDescOnce.Do(func() {
|
||||||
|
file_app_persistentstorage_filesystemstorage_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_app_persistentstorage_filesystemstorage_config_proto_rawDesc), len(file_app_persistentstorage_filesystemstorage_config_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_app_persistentstorage_filesystemstorage_config_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_app_persistentstorage_filesystemstorage_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
|
var file_app_persistentstorage_filesystemstorage_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||||
|
var file_app_persistentstorage_filesystemstorage_config_proto_goTypes = []any{
|
||||||
|
(StateStorageRoot)(0), // 0: v2ray.core.app.persistentstorage.filesystemstorage.StateStorageRoot
|
||||||
|
(*Config)(nil), // 1: v2ray.core.app.persistentstorage.filesystemstorage.Config
|
||||||
|
}
|
||||||
|
var file_app_persistentstorage_filesystemstorage_config_proto_depIdxs = []int32{
|
||||||
|
0, // 0: v2ray.core.app.persistentstorage.filesystemstorage.Config.state_storage_root:type_name -> v2ray.core.app.persistentstorage.filesystemstorage.StateStorageRoot
|
||||||
|
1, // [1:1] is the sub-list for method output_type
|
||||||
|
1, // [1:1] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_app_persistentstorage_filesystemstorage_config_proto_init() }
|
||||||
|
func file_app_persistentstorage_filesystemstorage_config_proto_init() {
|
||||||
|
if File_app_persistentstorage_filesystemstorage_config_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_app_persistentstorage_filesystemstorage_config_proto_rawDesc), len(file_app_persistentstorage_filesystemstorage_config_proto_rawDesc)),
|
||||||
|
NumEnums: 1,
|
||||||
|
NumMessages: 1,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_app_persistentstorage_filesystemstorage_config_proto_goTypes,
|
||||||
|
DependencyIndexes: file_app_persistentstorage_filesystemstorage_config_proto_depIdxs,
|
||||||
|
EnumInfos: file_app_persistentstorage_filesystemstorage_config_proto_enumTypes,
|
||||||
|
MessageInfos: file_app_persistentstorage_filesystemstorage_config_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_app_persistentstorage_filesystemstorage_config_proto = out.File
|
||||||
|
file_app_persistentstorage_filesystemstorage_config_proto_goTypes = nil
|
||||||
|
file_app_persistentstorage_filesystemstorage_config_proto_depIdxs = nil
|
||||||
|
}
|
||||||
23
app/persistentstorage/filesystemstorage/config.proto
Normal file
23
app/persistentstorage/filesystemstorage/config.proto
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package v2ray.core.app.persistentstorage.filesystemstorage;
|
||||||
|
option csharp_namespace = "V2Ray.Core.App.Persistentstorage.Filesystemstorage";
|
||||||
|
option go_package = "github.com/v2fly/v2ray-core/v5/app/persistentstorage/filesystemstorage";
|
||||||
|
option java_package = "com.v2ray.core.persistentstorage.filesystemstorage";
|
||||||
|
option java_multiple_files = true;
|
||||||
|
|
||||||
|
import "common/protoext/extensions.proto";
|
||||||
|
|
||||||
|
enum StateStorageRoot {
|
||||||
|
WorkDir = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Config {
|
||||||
|
option (v2ray.core.common.protoext.message_opt).type = "service";
|
||||||
|
option (v2ray.core.common.protoext.message_opt).short_name = "filesystemstorage";
|
||||||
|
|
||||||
|
StateStorageRoot state_storage_root = 1;
|
||||||
|
string instance_name = 4;
|
||||||
|
|
||||||
|
bool protojson = 5;
|
||||||
|
}
|
||||||
133
app/persistentstorage/filesystemstorage/fs.go
Normal file
133
app/persistentstorage/filesystemstorage/fs.go
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
package filesystemstorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/app/persistentstorage/protostorage"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/features/extension/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newFileSystemStorage(ctx context.Context, config *Config) storage.ScopedPersistentStorageService {
|
||||||
|
appEnvironment := envctx.EnvironmentFromContext(ctx).(environment.AppEnvironment)
|
||||||
|
fss := &fileSystemStorage{
|
||||||
|
fs: appEnvironment,
|
||||||
|
pathRoot: config.InstanceName,
|
||||||
|
currentLocation: nil,
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
|
||||||
|
protoStorageInst := protostorage.NewProtoStorage(fss, config.Protojson)
|
||||||
|
fss.proto = protoStorageInst
|
||||||
|
return fss
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileSystemStorage struct {
|
||||||
|
fs environment.FileSystemCapabilitySet
|
||||||
|
proto protostorage.ProtoPersistentStorage
|
||||||
|
|
||||||
|
pathRoot string
|
||||||
|
currentLocation []string
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) Type() interface{} {
|
||||||
|
return storage.ScopedPersistentStorageServiceType
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) Start() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) PutProto(ctx context.Context, key string, pb proto.Message) error {
|
||||||
|
return f.proto.PutProto(ctx, key, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) GetProto(ctx context.Context, key string, pb proto.Message) error {
|
||||||
|
return f.proto.GetProto(ctx, key, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) ScopedPersistentStorageEngine() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) Put(ctx context.Context, key []byte, value []byte) error {
|
||||||
|
finalPath := filepath.Join(f.pathRoot, filepath.Join(f.currentLocation...), string(key))
|
||||||
|
if value == nil {
|
||||||
|
return f.fs.RemoveFile()(finalPath)
|
||||||
|
}
|
||||||
|
writer, err := f.fs.OpenFileForWrite()(finalPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer writer.Close()
|
||||||
|
_, err = io.Copy(writer, io.NopCloser(bytes.NewReader(value)))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) Get(ctx context.Context, key []byte) ([]byte, error) {
|
||||||
|
finalPath := filepath.Join(f.pathRoot, filepath.Join(f.currentLocation...), string(key))
|
||||||
|
reader, err := f.fs.OpenFileForRead()(finalPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer reader.Close()
|
||||||
|
return io.ReadAll(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) List(ctx context.Context, keyPrefix []byte) ([][]byte, error) {
|
||||||
|
res, err := f.fs.ReadDir()(filepath.Join(f.pathRoot, filepath.Join(f.currentLocation...)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var result [][]byte
|
||||||
|
for _, entry := range res {
|
||||||
|
if !entry.IsDir() && bytes.HasPrefix([]byte(entry.Name()), keyPrefix) {
|
||||||
|
result = append(result, []byte(entry.Name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) Clear(ctx context.Context) {
|
||||||
|
allFile, err := f.List(ctx, []byte{})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, file := range allFile {
|
||||||
|
_ = f.Put(ctx, file, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) NarrowScope(ctx context.Context, key []byte) (storage.ScopedPersistentStorage, error) {
|
||||||
|
escapedKey := strings.ReplaceAll(string(key), "/", "_")
|
||||||
|
fss := &fileSystemStorage{
|
||||||
|
fs: f.fs,
|
||||||
|
pathRoot: f.pathRoot,
|
||||||
|
currentLocation: append(f.currentLocation, escapedKey),
|
||||||
|
config: f.config,
|
||||||
|
}
|
||||||
|
fss.proto = protostorage.NewProtoStorage(fss, f.config.Protojson)
|
||||||
|
return fss, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fileSystemStorage) DropScope(ctx context.Context, key []byte) error {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
||||||
|
return newFileSystemStorage(ctx, config.(*Config)), nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
51
app/persistentstorage/protostorage/protokv.go
Normal file
51
app/persistentstorage/protostorage/protokv.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package protostorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/features/extension/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ProtoPersistentStorage interface {
|
||||||
|
PutProto(ctx context.Context, key string, pb proto.Message) error
|
||||||
|
GetProto(ctx context.Context, key string, pb proto.Message) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type protoStorage struct {
|
||||||
|
storage storage.ScopedPersistentStorage
|
||||||
|
textFormat bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *protoStorage) PutProto(ctx context.Context, key string, pb proto.Message) error {
|
||||||
|
if !p.textFormat {
|
||||||
|
data, err := proto.Marshal(pb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.storage.Put(ctx, []byte(key), data)
|
||||||
|
} else {
|
||||||
|
protojsonStr := protojson.Format(pb)
|
||||||
|
return p.storage.Put(ctx, []byte(key), []byte(protojsonStr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *protoStorage) GetProto(ctx context.Context, key string, pb proto.Message) error {
|
||||||
|
data, err := p.storage.Get(ctx, []byte(key))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !p.textFormat {
|
||||||
|
return proto.Unmarshal(data, pb)
|
||||||
|
}
|
||||||
|
return protojson.Unmarshal(data, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProtoStorage(storage storage.ScopedPersistentStorage, textFormat bool) ProtoPersistentStorage {
|
||||||
|
return &protoStorage{
|
||||||
|
storage: storage,
|
||||||
|
textFormat: textFormat,
|
||||||
|
}
|
||||||
|
}
|
||||||
5
app/persistentstorage/storage.go
Normal file
5
app/persistentstorage/storage.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package persistentstorage
|
||||||
|
|
||||||
|
import "github.com/v2fly/v2ray-core/v5/features/extension/storage"
|
||||||
|
|
||||||
|
type ScopedPersistentStorage = storage.ScopedPersistentStorage
|
||||||
@@ -5,18 +5,18 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
|
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment"
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment/transientstorageimpl"
|
|
||||||
|
|
||||||
"google.golang.org/protobuf/types/known/anypb"
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
|
|
||||||
core "github.com/v2fly/v2ray-core/v5"
|
core "github.com/v2fly/v2ray-core/v5"
|
||||||
"github.com/v2fly/v2ray-core/v5/app/policy"
|
"github.com/v2fly/v2ray-core/v5/app/policy"
|
||||||
. "github.com/v2fly/v2ray-core/v5/app/proxyman/outbound"
|
. "github.com/v2fly/v2ray-core/v5/app/proxyman/outbound"
|
||||||
"github.com/v2fly/v2ray-core/v5/app/stats"
|
"github.com/v2fly/v2ray-core/v5/app/stats"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/deferredpersistentstorage"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/filesystemimpl"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/transientstorageimpl"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/net"
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/serial"
|
"github.com/v2fly/v2ray-core/v5/common/serial"
|
||||||
"github.com/v2fly/v2ray-core/v5/features/outbound"
|
"github.com/v2fly/v2ray-core/v5/features/outbound"
|
||||||
@@ -50,7 +50,11 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
|
|||||||
v.AddFeature((outbound.Manager)(new(Manager)))
|
v.AddFeature((outbound.Manager)(new(Manager)))
|
||||||
ctx := toContext(context.Background(), v)
|
ctx := toContext(context.Background(), v)
|
||||||
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
||||||
rootEnv := environment.NewRootEnvImpl(ctx, transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener())
|
defaultFilesystemImpl := filesystemimpl.NewDefaultFileSystemDefaultImpl()
|
||||||
|
deferredPersistentStorageImpl := deferredpersistentstorage.NewDeferredPersistentStorage(ctx)
|
||||||
|
rootEnv := environment.NewRootEnvImpl(ctx,
|
||||||
|
transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener(),
|
||||||
|
defaultFilesystemImpl, deferredPersistentStorageImpl)
|
||||||
proxyEnvironment := rootEnv.ProxyEnvironment("o")
|
proxyEnvironment := rootEnv.ProxyEnvironment("o")
|
||||||
ctx = envctx.ContextWithEnvironment(ctx, proxyEnvironment)
|
ctx = envctx.ContextWithEnvironment(ctx, proxyEnvironment)
|
||||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||||
@@ -83,7 +87,11 @@ func TestOutboundWithStatCounter(t *testing.T) {
|
|||||||
v.AddFeature((outbound.Manager)(new(Manager)))
|
v.AddFeature((outbound.Manager)(new(Manager)))
|
||||||
ctx := toContext(context.Background(), v)
|
ctx := toContext(context.Background(), v)
|
||||||
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
||||||
rootEnv := environment.NewRootEnvImpl(ctx, transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener())
|
defaultFilesystemImpl := filesystemimpl.NewDefaultFileSystemDefaultImpl()
|
||||||
|
deferredPersistentStorageImpl := deferredpersistentstorage.NewDeferredPersistentStorage(ctx)
|
||||||
|
rootEnv := environment.NewRootEnvImpl(ctx,
|
||||||
|
transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener(),
|
||||||
|
defaultFilesystemImpl, deferredPersistentStorageImpl)
|
||||||
proxyEnvironment := rootEnv.ProxyEnvironment("o")
|
proxyEnvironment := rootEnv.ProxyEnvironment("o")
|
||||||
ctx = envctx.ContextWithEnvironment(ctx, proxyEnvironment)
|
ctx = envctx.ContextWithEnvironment(ctx, proxyEnvironment)
|
||||||
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package deferredpersistentstorage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/app/persistentstorage"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/errors"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/features/extension/storage"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DeferredPersistentStorage interface {
|
||||||
|
storage.ScopedPersistentStorage
|
||||||
|
ProvideInner(ctx context.Context, inner persistentstorage.ScopedPersistentStorage)
|
||||||
|
}
|
||||||
|
|
||||||
|
var errNotExist = errors.New("persistent storage does not exist")
|
||||||
|
|
||||||
|
type deferredPersistentStorage struct {
|
||||||
|
ready context.Context
|
||||||
|
done context.CancelFunc
|
||||||
|
inner persistentstorage.ScopedPersistentStorage
|
||||||
|
|
||||||
|
awaitingChildren []*deferredPersistentStorage
|
||||||
|
|
||||||
|
intoScopes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) ScopedPersistentStorageEngine() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) Put(ctx context.Context, key []byte, value []byte) error {
|
||||||
|
<-d.ready.Done()
|
||||||
|
if d.inner == nil {
|
||||||
|
return errNotExist
|
||||||
|
}
|
||||||
|
return d.inner.Put(ctx, key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) Get(ctx context.Context, key []byte) ([]byte, error) {
|
||||||
|
<-d.ready.Done()
|
||||||
|
if d.inner == nil {
|
||||||
|
return nil, errNotExist
|
||||||
|
}
|
||||||
|
return d.inner.Get(ctx, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) List(ctx context.Context, keyPrefix []byte) ([][]byte, error) {
|
||||||
|
<-d.ready.Done()
|
||||||
|
if d.inner == nil {
|
||||||
|
return nil, errNotExist
|
||||||
|
}
|
||||||
|
return d.inner.List(ctx, keyPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) Clear(ctx context.Context) {
|
||||||
|
<-d.ready.Done()
|
||||||
|
if d.inner == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d.inner.Clear(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) NarrowScope(ctx context.Context, key []byte) (storage.ScopedPersistentStorage, error) {
|
||||||
|
if d.ready.Err() != nil {
|
||||||
|
return d.inner.NarrowScope(ctx, key)
|
||||||
|
}
|
||||||
|
ready, done := context.WithCancel(ctx)
|
||||||
|
swallowCopyScopes := d.intoScopes
|
||||||
|
dps := &deferredPersistentStorage{
|
||||||
|
ready: ready,
|
||||||
|
done: done,
|
||||||
|
inner: nil,
|
||||||
|
intoScopes: append(swallowCopyScopes, string(key)),
|
||||||
|
}
|
||||||
|
d.awaitingChildren = append(d.awaitingChildren, dps)
|
||||||
|
return dps, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) DropScope(ctx context.Context, key []byte) error {
|
||||||
|
<-d.ready.Done()
|
||||||
|
if d.inner == nil {
|
||||||
|
return errNotExist
|
||||||
|
}
|
||||||
|
return d.inner.DropScope(ctx, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *deferredPersistentStorage) ProvideInner(ctx context.Context, inner persistentstorage.ScopedPersistentStorage) {
|
||||||
|
d.inner = inner
|
||||||
|
if inner != nil {
|
||||||
|
for _, scope := range d.intoScopes {
|
||||||
|
newScope, err := inner.NarrowScope(ctx, []byte(scope))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
d.inner = newScope
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, child := range d.awaitingChildren {
|
||||||
|
child.ProvideInner(ctx, d.inner)
|
||||||
|
}
|
||||||
|
d.done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDeferredPersistentStorage(ctx context.Context) DeferredPersistentStorage {
|
||||||
|
ready, done := context.WithCancel(ctx)
|
||||||
|
return &deferredPersistentStorage{
|
||||||
|
ready: ready,
|
||||||
|
done: done,
|
||||||
|
inner: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,14 @@ import (
|
|||||||
|
|
||||||
type fileSystemDefaultImpl struct{}
|
type fileSystemDefaultImpl struct{}
|
||||||
|
|
||||||
|
func (f fileSystemDefaultImpl) ReadDir() fsifce.FileReadDirFunc {
|
||||||
|
return filesystem.NewFileReadDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fileSystemDefaultImpl) RemoveFile() fsifce.FileRemoveFunc {
|
||||||
|
return filesystem.NewFileRemover
|
||||||
|
}
|
||||||
|
|
||||||
func (f fileSystemDefaultImpl) OpenFileForReadSeek() fsifce.FileSeekerFunc {
|
func (f fileSystemDefaultImpl) OpenFileForReadSeek() fsifce.FileSeekerFunc {
|
||||||
return filesystem.NewFileSeeker
|
return filesystem.NewFileSeeker
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,6 @@ type FileSystemCapabilitySet interface {
|
|||||||
OpenFileForReadSeek() fsifce.FileSeekerFunc
|
OpenFileForReadSeek() fsifce.FileSeekerFunc
|
||||||
OpenFileForRead() fsifce.FileReaderFunc
|
OpenFileForRead() fsifce.FileReaderFunc
|
||||||
OpenFileForWrite() fsifce.FileWriterFunc
|
OpenFileForWrite() fsifce.FileWriterFunc
|
||||||
|
ReadDir() fsifce.FileReadDirFunc
|
||||||
|
RemoveFile() fsifce.FileRemoveFunc
|
||||||
}
|
}
|
||||||
|
|||||||
33
common/environment/filesystemimpl/fsimpl.go
Normal file
33
common/environment/filesystemimpl/fsimpl.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package filesystemimpl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/platform/filesystem"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/platform/filesystem/fsifce"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewDefaultFileSystemDefaultImpl() environment.FileSystemCapabilitySet {
|
||||||
|
return fsCapImpl{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type fsCapImpl struct{}
|
||||||
|
|
||||||
|
func (f fsCapImpl) OpenFileForReadSeek() fsifce.FileSeekerFunc {
|
||||||
|
return filesystem.NewFileSeeker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fsCapImpl) OpenFileForRead() fsifce.FileReaderFunc {
|
||||||
|
return filesystem.NewFileReader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fsCapImpl) OpenFileForWrite() fsifce.FileWriterFunc {
|
||||||
|
return filesystem.NewFileWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fsCapImpl) ReadDir() fsifce.FileReadDirFunc {
|
||||||
|
return filesystem.NewFileReadDir
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f fsCapImpl) RemoveFile() fsifce.FileRemoveFunc {
|
||||||
|
return filesystem.NewFileRemover
|
||||||
|
}
|
||||||
@@ -11,19 +11,24 @@ import (
|
|||||||
|
|
||||||
func NewRootEnvImpl(ctx context.Context, transientStorage storage.ScopedTransientStorage,
|
func NewRootEnvImpl(ctx context.Context, transientStorage storage.ScopedTransientStorage,
|
||||||
systemDialer internet.SystemDialer, systemListener internet.SystemListener,
|
systemDialer internet.SystemDialer, systemListener internet.SystemListener,
|
||||||
|
filesystem FileSystemCapabilitySet, persistStorage storage.ScopedPersistentStorage,
|
||||||
) RootEnvironment {
|
) RootEnvironment {
|
||||||
return &rootEnvImpl{
|
return &rootEnvImpl{
|
||||||
transientStorage: transientStorage,
|
transientStorage: transientStorage,
|
||||||
systemListener: systemListener,
|
systemListener: systemListener,
|
||||||
systemDialer: systemDialer,
|
systemDialer: systemDialer,
|
||||||
|
filesystem: filesystem,
|
||||||
|
persistStorage: persistStorage,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type rootEnvImpl struct {
|
type rootEnvImpl struct {
|
||||||
|
persistStorage storage.ScopedPersistentStorage
|
||||||
transientStorage storage.ScopedTransientStorage
|
transientStorage storage.ScopedTransientStorage
|
||||||
systemDialer internet.SystemDialer
|
systemDialer internet.SystemDialer
|
||||||
systemListener internet.SystemListener
|
systemListener internet.SystemListener
|
||||||
|
filesystem FileSystemCapabilitySet
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
@@ -37,10 +42,16 @@ func (r *rootEnvImpl) AppEnvironment(tag string) AppEnvironment {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
persistStorage, err := r.persistStorage.NarrowScope(r.ctx, []byte(tag))
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return &appEnvImpl{
|
return &appEnvImpl{
|
||||||
transientStorage: transientStorage,
|
transientStorage: transientStorage,
|
||||||
|
persistStorage: persistStorage,
|
||||||
systemListener: r.systemListener,
|
systemListener: r.systemListener,
|
||||||
systemDialer: r.systemDialer,
|
systemDialer: r.systemDialer,
|
||||||
|
filesystem: r.filesystem,
|
||||||
ctx: r.ctx,
|
ctx: r.ctx,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,9 +78,11 @@ func (r *rootEnvImpl) DropProxyEnvironment(tag string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type appEnvImpl struct {
|
type appEnvImpl struct {
|
||||||
|
persistStorage storage.ScopedPersistentStorage
|
||||||
transientStorage storage.ScopedTransientStorage
|
transientStorage storage.ScopedTransientStorage
|
||||||
systemDialer internet.SystemDialer
|
systemDialer internet.SystemDialer
|
||||||
systemListener internet.SystemListener
|
systemListener internet.SystemListener
|
||||||
|
filesystem FileSystemCapabilitySet
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
}
|
}
|
||||||
@@ -95,19 +108,27 @@ func (a *appEnvImpl) OutboundDialer() tagged.DialFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *appEnvImpl) OpenFileForReadSeek() fsifce.FileSeekerFunc {
|
func (a *appEnvImpl) OpenFileForReadSeek() fsifce.FileSeekerFunc {
|
||||||
panic("implement me")
|
return a.filesystem.OpenFileForReadSeek()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *appEnvImpl) OpenFileForRead() fsifce.FileReaderFunc {
|
func (a *appEnvImpl) OpenFileForRead() fsifce.FileReaderFunc {
|
||||||
panic("implement me")
|
return a.filesystem.OpenFileForRead()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *appEnvImpl) OpenFileForWrite() fsifce.FileWriterFunc {
|
func (a *appEnvImpl) OpenFileForWrite() fsifce.FileWriterFunc {
|
||||||
panic("implement me")
|
return a.filesystem.OpenFileForWrite()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *appEnvImpl) ReadDir() fsifce.FileReadDirFunc {
|
||||||
|
return a.filesystem.ReadDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *appEnvImpl) RemoveFile() fsifce.FileRemoveFunc {
|
||||||
|
return a.filesystem.RemoveFile()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *appEnvImpl) PersistentStorage() storage.ScopedPersistentStorage {
|
func (a *appEnvImpl) PersistentStorage() storage.ScopedPersistentStorage {
|
||||||
panic("implement me")
|
return a.persistStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *appEnvImpl) TransientStorage() storage.ScopedTransientStorage {
|
func (a *appEnvImpl) TransientStorage() storage.ScopedTransientStorage {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package filesystem
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/buf"
|
"github.com/v2fly/v2ray-core/v5/common/buf"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/platform"
|
"github.com/v2fly/v2ray-core/v5/common/platform"
|
||||||
@@ -18,9 +19,17 @@ var NewFileReader fsifce.FileReaderFunc = func(path string) (io.ReadCloser, erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
var NewFileWriter fsifce.FileWriterFunc = func(path string) (io.WriteCloser, error) {
|
var NewFileWriter fsifce.FileWriterFunc = func(path string) (io.WriteCloser, error) {
|
||||||
|
basePath := filepath.Dir(path)
|
||||||
|
if err := os.MkdirAll(basePath, 0o700); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return os.Create(path)
|
return os.Create(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var NewFileRemover fsifce.FileRemoveFunc = os.Remove
|
||||||
|
|
||||||
|
var NewFileReadDir fsifce.FileReadDirFunc = os.ReadDir
|
||||||
|
|
||||||
func ReadFile(path string) ([]byte, error) {
|
func ReadFile(path string) ([]byte, error) {
|
||||||
reader, err := NewFileReader(path)
|
reader, err := NewFileReader(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
package fsifce
|
package fsifce
|
||||||
|
|
||||||
import "io"
|
import (
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
)
|
||||||
|
|
||||||
type FileSeekerFunc func(path string) (io.ReadSeekCloser, error)
|
type FileSeekerFunc func(path string) (io.ReadSeekCloser, error)
|
||||||
|
|
||||||
type FileReaderFunc func(path string) (io.ReadCloser, error)
|
type FileReaderFunc func(path string) (io.ReadCloser, error)
|
||||||
|
|
||||||
type FileWriterFunc func(path string) (io.WriteCloser, error)
|
type FileWriterFunc func(path string) (io.WriteCloser, error)
|
||||||
|
|
||||||
|
type FileReadDirFunc func(path string) ([]fs.DirEntry, error)
|
||||||
|
|
||||||
|
type FileRemoveFunc func(path string) error
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package storage
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/features"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ScopedPersistentStorage interface {
|
type ScopedPersistentStorage interface {
|
||||||
@@ -23,3 +25,10 @@ type ScopedTransientStorage interface {
|
|||||||
NarrowScope(ctx context.Context, key string) (ScopedTransientStorage, error)
|
NarrowScope(ctx context.Context, key string) (ScopedTransientStorage, error)
|
||||||
DropScope(ctx context.Context, key string) error
|
DropScope(ctx context.Context, key string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ScopedPersistentStorageService interface {
|
||||||
|
ScopedPersistentStorage
|
||||||
|
features.Feature
|
||||||
|
}
|
||||||
|
|
||||||
|
var ScopedPersistentStorageServiceType = (*ScopedPersistentStorageService)(nil)
|
||||||
|
|||||||
@@ -108,9 +108,9 @@ func getProjectProtocVersion(url string) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("can not read from body")
|
return "", fmt.Errorf("can not read from body")
|
||||||
}
|
}
|
||||||
versionRegexp := regexp.MustCompile(`\/\/\s*protoc\s*v(\d+\.\d+\.\d+)`)
|
versionRegexp := regexp.MustCompile(`\/\/\s*protoc\s*v(\d+\.(\d+\.\d+))`)
|
||||||
matched := versionRegexp.FindStringSubmatch(string(body))
|
matched := versionRegexp.FindStringSubmatch(string(body))
|
||||||
return matched[1], nil
|
return matched[2], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getInstalledProtocVersion(protocPath string) (string, error) {
|
func getInstalledProtocVersion(protocPath string) (string, error) {
|
||||||
@@ -126,10 +126,6 @@ func getInstalledProtocVersion(protocPath string) (string, error) {
|
|||||||
if len(matched) == 0 {
|
if len(matched) == 0 {
|
||||||
return "", errors.New("can not parse protoc version")
|
return "", errors.New("can not parse protoc version")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matched) == 2 {
|
|
||||||
installedVersion += "4." // in contrast to getProjectProtocVersion()
|
|
||||||
}
|
|
||||||
installedVersion += matched[1]
|
installedVersion += matched[1]
|
||||||
fmt.Println("Using protoc version: " + installedVersion)
|
fmt.Println("Using protoc version: " + installedVersion)
|
||||||
return installedVersion, nil
|
return installedVersion, nil
|
||||||
@@ -139,9 +135,6 @@ func parseVersion(s string, width int) int64 {
|
|||||||
strList := strings.Split(s, ".")
|
strList := strings.Split(s, ".")
|
||||||
format := fmt.Sprintf("%%s%%0%ds", width)
|
format := fmt.Sprintf("%%s%%0%ds", width)
|
||||||
v := ""
|
v := ""
|
||||||
if len(strList) == 2 {
|
|
||||||
strList = append([]string{"4"}, strList...)
|
|
||||||
}
|
|
||||||
for _, value := range strList {
|
for _, value := range strList {
|
||||||
v = fmt.Sprintf(format, v, value)
|
v = fmt.Sprintf(format, v, value)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import (
|
|||||||
_ "github.com/v2fly/v2ray-core/v5/app/commander/webcommander"
|
_ "github.com/v2fly/v2ray-core/v5/app/commander/webcommander"
|
||||||
_ "github.com/v2fly/v2ray-core/v5/app/instman"
|
_ "github.com/v2fly/v2ray-core/v5/app/instman"
|
||||||
_ "github.com/v2fly/v2ray-core/v5/app/observatory"
|
_ "github.com/v2fly/v2ray-core/v5/app/observatory"
|
||||||
|
_ "github.com/v2fly/v2ray-core/v5/app/persistentstorage/filesystemstorage"
|
||||||
_ "github.com/v2fly/v2ray-core/v5/app/tun"
|
_ "github.com/v2fly/v2ray-core/v5/app/tun"
|
||||||
|
|
||||||
// Inbound and outbound proxies.
|
// Inbound and outbound proxies.
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/deferredpersistentstorage"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/filesystemimpl"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment"
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
|
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
|
||||||
@@ -25,7 +28,11 @@ import (
|
|||||||
func TestDialAndListen(t *testing.T) {
|
func TestDialAndListen(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
||||||
rootEnv := environment.NewRootEnvImpl(ctx, transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener())
|
defaultFilesystemImpl := filesystemimpl.NewDefaultFileSystemDefaultImpl()
|
||||||
|
deferredPersistentStorageImpl := deferredpersistentstorage.NewDeferredPersistentStorage(ctx)
|
||||||
|
rootEnv := environment.NewRootEnvImpl(ctx,
|
||||||
|
transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener(),
|
||||||
|
defaultFilesystemImpl, deferredPersistentStorageImpl)
|
||||||
proxyEnvironment := rootEnv.ProxyEnvironment("o")
|
proxyEnvironment := rootEnv.ProxyEnvironment("o")
|
||||||
transportEnvironment, err := proxyEnvironment.NarrowScopeToTransport("kcp")
|
transportEnvironment, err := proxyEnvironment.NarrowScopeToTransport("kcp")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common/net"
|
"github.com/v2fly/v2ray-core/v5/common/net"
|
||||||
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
"github.com/v2fly/v2ray-core/v5/transport/internet"
|
||||||
)
|
)
|
||||||
|
|||||||
19
v2ray.go
19
v2ray.go
@@ -5,6 +5,10 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
|
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/deferredpersistentstorage"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/common/environment/filesystemimpl"
|
||||||
|
"github.com/v2fly/v2ray-core/v5/features/extension/storage"
|
||||||
|
|
||||||
"github.com/v2fly/v2ray-core/v5/common"
|
"github.com/v2fly/v2ray-core/v5/common"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment"
|
"github.com/v2fly/v2ray-core/v5/common/environment"
|
||||||
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
|
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
|
||||||
@@ -205,7 +209,14 @@ func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
defaultNetworkImpl := systemnetworkimpl.NewSystemNetworkDefault()
|
||||||
server.env = environment.NewRootEnvImpl(server.ctx, transientstorageimpl.NewScopedTransientStorageImpl(), defaultNetworkImpl.Dialer(), defaultNetworkImpl.Listener())
|
defaultFilesystemImpl := filesystemimpl.NewDefaultFileSystemDefaultImpl()
|
||||||
|
deferredPersistentStorageImpl := deferredpersistentstorage.NewDeferredPersistentStorage(server.ctx)
|
||||||
|
server.env = environment.NewRootEnvImpl(server.ctx,
|
||||||
|
transientstorageimpl.NewScopedTransientStorageImpl(),
|
||||||
|
defaultNetworkImpl.Dialer(),
|
||||||
|
defaultNetworkImpl.Listener(),
|
||||||
|
defaultFilesystemImpl,
|
||||||
|
deferredPersistentStorageImpl)
|
||||||
|
|
||||||
for _, appSettings := range config.App {
|
for _, appSettings := range config.App {
|
||||||
settings, err := serial.GetInstanceOf(appSettings)
|
settings, err := serial.GetInstanceOf(appSettings)
|
||||||
@@ -247,6 +258,12 @@ func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
|
|||||||
return true, newError("not all dependency are resolved.")
|
return true, newError("not all dependency are resolved.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if persistentStorageService := server.GetFeature(storage.ScopedPersistentStorageServiceType); persistentStorageService != nil {
|
||||||
|
deferredPersistentStorageImpl.ProvideInner(server.ctx, persistentStorageService.(storage.ScopedPersistentStorage))
|
||||||
|
} else {
|
||||||
|
deferredPersistentStorageImpl.ProvideInner(server.ctx, nil)
|
||||||
|
}
|
||||||
|
|
||||||
if err := addInboundHandlers(server, config.Inbound); err != nil {
|
if err := addInboundHandlers(server, config.Inbound); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user