1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2025-07-05 16:38:17 -04: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:
Xiaokang Wang (Shelikhoo) 2025-02-05 20:36:40 +00:00 committed by GitHub
parent 3ee9045697
commit 78cd513b82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 771 additions and 58 deletions

View File

@ -1,8 +1,5 @@
run:
timeout: 5m
skip-files:
- generated.*
- .pb.go
issues:
new: true
@ -13,6 +10,9 @@ issues:
- linters:
- stylecheck
text: "ST1016:"
exclude-files:
- generated.*
- .pb.go
linters:
enable:

View File

@ -53,7 +53,7 @@ jobs:
cp ../*.deb ./
- name: Upload artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: v2ray-debian-packages
path: ./*.deb

View File

@ -188,7 +188,7 @@ jobs:
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
- name: Upload ZIP file to Artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
path: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
@ -217,7 +217,7 @@ jobs:
with:
go-version: ^1.23
- uses: actions/download-artifact@v3
- uses: actions/download-artifact@v4
with:
path: build_artifacts
@ -252,17 +252,17 @@ jobs:
openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: Release.unsigned
path: build_artifacts/Release.unsigned
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: Release.unsigned.dgst
path: build_artifacts/Release.unsigned.dgst
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: v2ray-extra.zip
path: build_artifacts/v2ray-extra.zip

View File

@ -365,11 +365,12 @@ func (x *Intensity) GetProbeInterval() uint32 {
type Config struct {
state protoimpl.MessageState `protogen:"open.v1"`
// @Document The selectors for outbound under observation
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"`
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
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"`
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
PersistentProbeResult bool `protobuf:"varint,5,opt,name=persistent_probe_result,json=persistentProbeResult,proto3" json:"persistent_probe_result,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *Config) Reset() {
@ -423,6 +424,13 @@ func (x *Config) GetProbeInterval() int64 {
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_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,
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,
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,
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,
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,
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,
0x82, 0xb5, 0x18, 0x20, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x15, 0x62,
0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
0x74, 0x6f, 0x72, 0x79, 0x42, 0x6f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61,
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72,
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x2e, 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, 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,
0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x36,
0x0a, 0x17, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f,
0x62, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
0x15, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x62, 0x65,
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3a, 0x24, 0x82, 0xb5, 0x18, 0x20, 0x0a, 0x07, 0x73, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x15, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e,
0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x6f, 0x0a, 0x1e,
0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01,
0x5a, 0x2e, 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, 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 (

View File

@ -84,4 +84,6 @@ message Config {
string probe_url = 3;
int64 probe_interval = 4;
bool persistent_probe_result = 5;
}

View File

@ -12,6 +12,11 @@ import (
"sync"
"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"
core "github.com/v2fly/v2ray-core/v5"
@ -34,7 +39,10 @@ type Observer struct {
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) {
@ -47,6 +55,24 @@ func (o *Observer) Type() interface{} {
func (o *Observer) Start() error {
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()
go o.background()
}
@ -195,6 +221,12 @@ func (o *Observer) updateStatusForResult(outbound string, result *ProbeResult) {
status.LastErrorReason = result.LastErrorReason
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 {
@ -206,19 +238,33 @@ func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
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) {
var outboundManager outbound.Manager
obs := &Observer{
config: config,
ctx: ctx,
}
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
outboundManager = om
obs.ohm = om
})
if err != nil {
return nil, newError("Cannot get depended features").Base(err)
}
return &Observer{
config: config,
ctx: ctx,
ohm: outboundManager,
}, nil
return obs, nil
}
func init() {

View 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
}

View 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;
}

View 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
}))
}

View 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,
}
}

View File

@ -0,0 +1,5 @@
package persistentstorage
import "github.com/v2fly/v2ray-core/v5/features/extension/storage"
type ScopedPersistentStorage = storage.ScopedPersistentStorage

View File

@ -5,18 +5,18 @@ import (
"testing"
_ "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"
core "github.com/v2fly/v2ray-core/v5"
"github.com/v2fly/v2ray-core/v5/app/policy"
. "github.com/v2fly/v2ray-core/v5/app/proxyman/outbound"
"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/serial"
"github.com/v2fly/v2ray-core/v5/features/outbound"
@ -50,7 +50,11 @@ func TestOutboundWithoutStatCounter(t *testing.T) {
v.AddFeature((outbound.Manager)(new(Manager)))
ctx := toContext(context.Background(), v)
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")
ctx = envctx.ContextWithEnvironment(ctx, proxyEnvironment)
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{
@ -83,7 +87,11 @@ func TestOutboundWithStatCounter(t *testing.T) {
v.AddFeature((outbound.Manager)(new(Manager)))
ctx := toContext(context.Background(), v)
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")
ctx = envctx.ContextWithEnvironment(ctx, proxyEnvironment)
h, _ := NewHandler(ctx, &core.OutboundHandlerConfig{

View File

@ -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,
}
}

View File

@ -8,6 +8,14 @@ import (
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 {
return filesystem.NewFileSeeker
}

View File

@ -6,4 +6,6 @@ type FileSystemCapabilitySet interface {
OpenFileForReadSeek() fsifce.FileSeekerFunc
OpenFileForRead() fsifce.FileReaderFunc
OpenFileForWrite() fsifce.FileWriterFunc
ReadDir() fsifce.FileReadDirFunc
RemoveFile() fsifce.FileRemoveFunc
}

View 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
}

View File

@ -11,19 +11,24 @@ import (
func NewRootEnvImpl(ctx context.Context, transientStorage storage.ScopedTransientStorage,
systemDialer internet.SystemDialer, systemListener internet.SystemListener,
filesystem FileSystemCapabilitySet, persistStorage storage.ScopedPersistentStorage,
) RootEnvironment {
return &rootEnvImpl{
transientStorage: transientStorage,
systemListener: systemListener,
systemDialer: systemDialer,
filesystem: filesystem,
persistStorage: persistStorage,
ctx: ctx,
}
}
type rootEnvImpl struct {
persistStorage storage.ScopedPersistentStorage
transientStorage storage.ScopedTransientStorage
systemDialer internet.SystemDialer
systemListener internet.SystemListener
filesystem FileSystemCapabilitySet
ctx context.Context
}
@ -37,10 +42,16 @@ func (r *rootEnvImpl) AppEnvironment(tag string) AppEnvironment {
if err != nil {
return nil
}
persistStorage, err := r.persistStorage.NarrowScope(r.ctx, []byte(tag))
if err != nil {
return nil
}
return &appEnvImpl{
transientStorage: transientStorage,
persistStorage: persistStorage,
systemListener: r.systemListener,
systemDialer: r.systemDialer,
filesystem: r.filesystem,
ctx: r.ctx,
}
}
@ -67,9 +78,11 @@ func (r *rootEnvImpl) DropProxyEnvironment(tag string) error {
}
type appEnvImpl struct {
persistStorage storage.ScopedPersistentStorage
transientStorage storage.ScopedTransientStorage
systemDialer internet.SystemDialer
systemListener internet.SystemListener
filesystem FileSystemCapabilitySet
ctx context.Context
}
@ -95,19 +108,27 @@ func (a *appEnvImpl) OutboundDialer() tagged.DialFunc {
}
func (a *appEnvImpl) OpenFileForReadSeek() fsifce.FileSeekerFunc {
panic("implement me")
return a.filesystem.OpenFileForReadSeek()
}
func (a *appEnvImpl) OpenFileForRead() fsifce.FileReaderFunc {
panic("implement me")
return a.filesystem.OpenFileForRead()
}
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 {
panic("implement me")
return a.persistStorage
}
func (a *appEnvImpl) TransientStorage() storage.ScopedTransientStorage {

View File

@ -3,6 +3,7 @@ package filesystem
import (
"io"
"os"
"path/filepath"
"github.com/v2fly/v2ray-core/v5/common/buf"
"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) {
basePath := filepath.Dir(path)
if err := os.MkdirAll(basePath, 0o700); err != nil {
return nil, err
}
return os.Create(path)
}
var NewFileRemover fsifce.FileRemoveFunc = os.Remove
var NewFileReadDir fsifce.FileReadDirFunc = os.ReadDir
func ReadFile(path string) ([]byte, error) {
reader, err := NewFileReader(path)
if err != nil {

View File

@ -1,9 +1,16 @@
package fsifce
import "io"
import (
"io"
"io/fs"
)
type FileSeekerFunc func(path string) (io.ReadSeekCloser, error)
type FileReaderFunc func(path string) (io.ReadCloser, error)
type FileWriterFunc func(path string) (io.WriteCloser, error)
type FileReadDirFunc func(path string) ([]fs.DirEntry, error)
type FileRemoveFunc func(path string) error

View File

@ -2,6 +2,8 @@ package storage
import (
"context"
"github.com/v2fly/v2ray-core/v5/features"
)
type ScopedPersistentStorage interface {
@ -23,3 +25,10 @@ type ScopedTransientStorage interface {
NarrowScope(ctx context.Context, key string) (ScopedTransientStorage, error)
DropScope(ctx context.Context, key string) error
}
type ScopedPersistentStorageService interface {
ScopedPersistentStorage
features.Feature
}
var ScopedPersistentStorageServiceType = (*ScopedPersistentStorageService)(nil)

View File

@ -108,9 +108,9 @@ func getProjectProtocVersion(url string) (string, error) {
if err != nil {
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))
return matched[1], nil
return matched[2], nil
}
func getInstalledProtocVersion(protocPath string) (string, error) {
@ -126,10 +126,6 @@ func getInstalledProtocVersion(protocPath string) (string, error) {
if len(matched) == 0 {
return "", errors.New("can not parse protoc version")
}
if len(matched) == 2 {
installedVersion += "4." // in contrast to getProjectProtocVersion()
}
installedVersion += matched[1]
fmt.Println("Using protoc version: " + installedVersion)
return installedVersion, nil
@ -139,9 +135,6 @@ func parseVersion(s string, width int) int64 {
strList := strings.Split(s, ".")
format := fmt.Sprintf("%%s%%0%ds", width)
v := ""
if len(strList) == 2 {
strList = append([]string{"4"}, strList...)
}
for _, value := range strList {
v = fmt.Sprintf(format, v, value)
}

View File

@ -34,6 +34,7 @@ import (
_ "github.com/v2fly/v2ray-core/v5/app/commander/webcommander"
_ "github.com/v2fly/v2ray-core/v5/app/instman"
_ "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"
// Inbound and outbound proxies.

View File

@ -7,6 +7,9 @@ import (
"testing"
"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/envctx"
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
@ -25,7 +28,11 @@ import (
func TestDialAndListen(t *testing.T) {
ctx := context.Background()
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")
transportEnvironment, err := proxyEnvironment.NarrowScopeToTransport("kcp")
if err != nil {

View File

@ -13,6 +13,7 @@ import (
"time"
"github.com/miekg/dns"
"github.com/v2fly/v2ray-core/v5/common/net"
"github.com/v2fly/v2ray-core/v5/transport/internet"
)

View File

@ -5,6 +5,10 @@ import (
"reflect"
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/environment"
"github.com/v2fly/v2ray-core/v5/common/environment/systemnetworkimpl"
@ -205,7 +209,14 @@ func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
}
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 {
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.")
}
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 {
return true, err
}