Skip to content

Commit 78cd513

Browse files
authored
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
1 parent 3ee9045 commit 78cd513

File tree

25 files changed

+771
-58
lines changed

25 files changed

+771
-58
lines changed

.github/linters/.golangci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
run:
22
timeout: 5m
3-
skip-files:
4-
- generated.*
5-
- .pb.go
63

74
issues:
85
new: true
@@ -13,6 +10,9 @@ issues:
1310
- linters:
1411
- stylecheck
1512
text: "ST1016:"
13+
exclude-files:
14+
- generated.*
15+
- .pb.go
1616

1717
linters:
1818
enable:

.github/workflows/deb.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
cp ../*.deb ./
5454
5555
- name: Upload artifact
56-
uses: actions/upload-artifact@v3
56+
uses: actions/upload-artifact@v4
5757
with:
5858
name: v2ray-debian-packages
5959
path: ./*.deb

.github/workflows/release.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ jobs:
188188
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
189189
190190
- name: Upload ZIP file to Artifacts
191-
uses: actions/upload-artifact@v3
191+
uses: actions/upload-artifact@v4
192192
with:
193193
name: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
194194
path: v2ray-${{ steps.get_filename.outputs.ASSET_NAME }}.zip
@@ -217,7 +217,7 @@ jobs:
217217
with:
218218
go-version: ^1.23
219219

220-
- uses: actions/download-artifact@v3
220+
- uses: actions/download-artifact@v4
221221
with:
222222
path: build_artifacts
223223

@@ -252,17 +252,17 @@ jobs:
252252
openssl dgst -sha256 $FILE | sed 's/([^)]*)//g' >>$DGST
253253
openssl dgst -sha512 $FILE | sed 's/([^)]*)//g' >>$DGST
254254
255-
- uses: actions/upload-artifact@v3
255+
- uses: actions/upload-artifact@v4
256256
with:
257257
name: Release.unsigned
258258
path: build_artifacts/Release.unsigned
259259

260-
- uses: actions/upload-artifact@v3
260+
- uses: actions/upload-artifact@v4
261261
with:
262262
name: Release.unsigned.dgst
263263
path: build_artifacts/Release.unsigned.dgst
264264

265-
- uses: actions/upload-artifact@v3
265+
- uses: actions/upload-artifact@v4
266266
with:
267267
name: v2ray-extra.zip
268268
path: build_artifacts/v2ray-extra.zip

app/observatory/config.pb.go

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,12 @@ func (x *Intensity) GetProbeInterval() uint32 {
365365
type Config struct {
366366
state protoimpl.MessageState `protogen:"open.v1"`
367367
// @Document The selectors for outbound under observation
368-
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
369-
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
370-
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
371-
unknownFields protoimpl.UnknownFields
372-
sizeCache protoimpl.SizeCache
368+
SubjectSelector []string `protobuf:"bytes,2,rep,name=subject_selector,json=subjectSelector,proto3" json:"subject_selector,omitempty"`
369+
ProbeUrl string `protobuf:"bytes,3,opt,name=probe_url,json=probeUrl,proto3" json:"probe_url,omitempty"`
370+
ProbeInterval int64 `protobuf:"varint,4,opt,name=probe_interval,json=probeInterval,proto3" json:"probe_interval,omitempty"`
371+
PersistentProbeResult bool `protobuf:"varint,5,opt,name=persistent_probe_result,json=persistentProbeResult,proto3" json:"persistent_probe_result,omitempty"`
372+
unknownFields protoimpl.UnknownFields
373+
sizeCache protoimpl.SizeCache
373374
}
374375

375376
func (x *Config) Reset() {
@@ -423,6 +424,13 @@ func (x *Config) GetProbeInterval() int64 {
423424
return 0
424425
}
425426

427+
func (x *Config) GetPersistentProbeResult() bool {
428+
if x != nil {
429+
return x.PersistentProbeResult
430+
}
431+
return false
432+
}
433+
426434
var File_app_observatory_config_proto protoreflect.FileDescriptor
427435

428436
var file_app_observatory_config_proto_rawDesc = string([]byte{
@@ -476,24 +484,28 @@ var file_app_observatory_config_proto_rawDesc = string([]byte{
476484
0x22, 0x32, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x12, 0x25, 0x0a,
477485
0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18,
478486
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65,
479-
0x72, 0x76, 0x61, 0x6c, 0x22, 0x9d, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
487+
0x72, 0x76, 0x61, 0x6c, 0x22, 0xd5, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
480488
0x29, 0x0a, 0x10, 0x73, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x73, 0x65, 0x6c, 0x65, 0x63,
481489
0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x75, 0x62, 0x6a, 0x65,
482490
0x63, 0x74, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x72,
483491
0x6f, 0x62, 0x65, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
484492
0x72, 0x6f, 0x62, 0x65, 0x55, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x62, 0x65,
485493
0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
486-
0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x3a, 0x24,
487-
0x82, 0xb5, 0x18, 0x20, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x15, 0x62,
488-
0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61,
489-
0x74, 0x6f, 0x72, 0x79, 0x42, 0x6f, 0x0a, 0x1e, 0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61,
490-
0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61, 0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72,
491-
0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62,
492-
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79,
493-
0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73,
494-
0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79,
495-
0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70, 0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76,
496-
0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
494+
0x0d, 0x70, 0x72, 0x6f, 0x62, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x36,
495+
0x0a, 0x17, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x70, 0x72, 0x6f,
496+
0x62, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52,
497+
0x15, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x62, 0x65,
498+
0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x3a, 0x24, 0x82, 0xb5, 0x18, 0x20, 0x0a, 0x07, 0x73, 0x65,
499+
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x15, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e,
500+
0x64, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x42, 0x6f, 0x0a, 0x1e,
501+
0x63, 0x6f, 0x6d, 0x2e, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x61,
502+
0x70, 0x70, 0x2e, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x50, 0x01,
503+
0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x32, 0x66,
504+
0x6c, 0x79, 0x2f, 0x76, 0x32, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x35,
505+
0x2f, 0x61, 0x70, 0x70, 0x2f, 0x6f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79,
506+
0xaa, 0x02, 0x1a, 0x56, 0x32, 0x52, 0x61, 0x79, 0x2e, 0x43, 0x6f, 0x72, 0x65, 0x2e, 0x41, 0x70,
507+
0x70, 0x2e, 0x4f, 0x62, 0x73, 0x65, 0x72, 0x76, 0x61, 0x74, 0x6f, 0x72, 0x79, 0x62, 0x06, 0x70,
508+
0x72, 0x6f, 0x74, 0x6f, 0x33,
497509
})
498510

499511
var (

app/observatory/config.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,6 @@ message Config {
8484
string probe_url = 3;
8585

8686
int64 probe_interval = 4;
87+
88+
bool persistent_probe_result = 5;
8789
}

app/observatory/observer.go

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ import (
1212
"sync"
1313
"time"
1414

15+
"github.com/v2fly/v2ray-core/v5/app/persistentstorage"
16+
"github.com/v2fly/v2ray-core/v5/app/persistentstorage/protostorage"
17+
"github.com/v2fly/v2ray-core/v5/common/environment"
18+
"github.com/v2fly/v2ray-core/v5/common/environment/envctx"
19+
1520
"github.com/golang/protobuf/proto"
1621

1722
core "github.com/v2fly/v2ray-core/v5"
@@ -34,7 +39,10 @@ type Observer struct {
3439

3540
finished *done.Instance
3641

37-
ohm outbound.Manager
42+
ohm outbound.Manager
43+
persistStorage persistentstorage.ScopedPersistentStorage
44+
45+
persistOutboundStatusProtoStorage protostorage.ProtoPersistentStorage
3846
}
3947

4048
func (o *Observer) GetObservation(ctx context.Context) (proto.Message, error) {
@@ -47,6 +55,24 @@ func (o *Observer) Type() interface{} {
4755

4856
func (o *Observer) Start() error {
4957
if o.config != nil && len(o.config.SubjectSelector) != 0 {
58+
if o.config.PersistentProbeResult {
59+
appEnvironment := envctx.EnvironmentFromContext(o.ctx).(environment.AppEnvironment)
60+
o.persistStorage = appEnvironment.PersistentStorage()
61+
62+
outboundStatusStorage, err := o.persistStorage.NarrowScope(o.ctx, []byte("outbound_status"))
63+
if err != nil {
64+
return newError("failed to get persistent storage for outbound_status").Base(err)
65+
}
66+
o.persistOutboundStatusProtoStorage = outboundStatusStorage.(protostorage.ProtoPersistentStorage)
67+
list, err := outboundStatusStorage.List(o.ctx, []byte(""))
68+
if err != nil {
69+
newError("failed to list persisted outbound status").Base(err).WriteToLog()
70+
} else {
71+
for _, v := range list {
72+
o.loadOutboundStatus(string(v))
73+
}
74+
}
75+
}
5076
o.finished = done.New()
5177
go o.background()
5278
}
@@ -195,6 +221,12 @@ func (o *Observer) updateStatusForResult(outbound string, result *ProbeResult) {
195221
status.LastErrorReason = result.LastErrorReason
196222
status.Delay = 99999999
197223
}
224+
if o.config.PersistentProbeResult {
225+
err := o.persistOutboundStatusProtoStorage.PutProto(o.ctx, outbound, status)
226+
if err != nil {
227+
newError("failed to persist outbound status").Base(err).WriteToLog()
228+
}
229+
}
198230
}
199231

200232
func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
@@ -206,19 +238,33 @@ func (o *Observer) findStatusLocationLockHolderOnly(outbound string) int {
206238
return -1
207239
}
208240

241+
func (o *Observer) loadOutboundStatus(name string) {
242+
if o.persistOutboundStatusProtoStorage == nil {
243+
return
244+
}
245+
status := &OutboundStatus{}
246+
err := o.persistOutboundStatusProtoStorage.GetProto(o.ctx, name, status)
247+
if err != nil {
248+
newError("failed to load outbound status").Base(err).WriteToLog()
249+
return
250+
}
251+
o.status = append(o.status, status)
252+
}
253+
209254
func New(ctx context.Context, config *Config) (*Observer, error) {
210-
var outboundManager outbound.Manager
255+
obs := &Observer{
256+
config: config,
257+
ctx: ctx,
258+
}
259+
211260
err := core.RequireFeatures(ctx, func(om outbound.Manager) {
212-
outboundManager = om
261+
obs.ohm = om
213262
})
214263
if err != nil {
215264
return nil, newError("Cannot get depended features").Base(err)
216265
}
217-
return &Observer{
218-
config: config,
219-
ctx: ctx,
220-
ohm: outboundManager,
221-
}, nil
266+
267+
return obs, nil
222268
}
223269

224270
func init() {

0 commit comments

Comments
 (0)