Compare commits
378 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f0f895424 | ||
|
|
07a3bdc618 | ||
|
|
7e348c196e | ||
|
|
51e5885e76 | ||
|
|
50d7912f62 | ||
|
|
3869148fc8 | ||
|
|
a0af4fb30c | ||
|
|
c374b8565b | ||
|
|
7e8b405555 | ||
|
|
c3439c5abe | ||
|
|
d4a8787356 | ||
|
|
23b27575a0 | ||
|
|
8d8a887c42 | ||
|
|
1229c967ba | ||
|
|
d35f65f86d | ||
|
|
0a8ce0f961 | ||
|
|
8092481d26 | ||
|
|
764014e49a | ||
|
|
71cc6d7a88 | ||
|
|
f3af831cf2 | ||
|
|
78fde575d7 | ||
|
|
6e5af34877 | ||
|
|
8d1853e991 | ||
|
|
859299c712 | ||
|
|
7fbb0013b0 | ||
|
|
837cfbd03b | ||
|
|
cdc5d72cfa | ||
|
|
8dcf5c5b90 | ||
|
|
67fe6ac3d8 | ||
|
|
438eaba4d5 | ||
|
|
3c8baa99d5 | ||
|
|
e70658f311 | ||
|
|
2dd10cf5a1 | ||
|
|
96781a784b | ||
|
|
9748fbb076 | ||
|
|
aa5e4378ab | ||
|
|
a7de149fd7 | ||
|
|
ae38be36f5 | ||
|
|
a20e989211 | ||
|
|
579f47ba0d | ||
|
|
24cad87954 | ||
|
|
84d72cd110 | ||
|
|
c0cd46a5aa | ||
|
|
98613c43ca | ||
|
|
555960e210 | ||
|
|
a18ae5582b | ||
|
|
6d6894591c | ||
|
|
984b97fc14 | ||
|
|
a7f35d4495 | ||
|
|
add92cfa7c | ||
|
|
6079e76be5 | ||
|
|
166c7cb2f5 | ||
|
|
dbd3ca44c2 | ||
|
|
ae495dde54 | ||
|
|
4ae25b2f34 | ||
|
|
cdfb621c59 | ||
|
|
29e8df7d2e | ||
|
|
72ff947d95 | ||
|
|
3edaac5739 | ||
|
|
5777a97119 | ||
|
|
aeddbc1dcc | ||
|
|
2f3e409487 | ||
|
|
aa133bb50b | ||
|
|
3bc79a4ba1 | ||
|
|
064a04fbad | ||
|
|
39ed13cf8a | ||
|
|
a1edacb196 | ||
|
|
c9f79e4b47 | ||
|
|
40c1498226 | ||
|
|
390061f9bd | ||
|
|
42324a2c9e | ||
|
|
b9b4ca6360 | ||
|
|
565697bc0b | ||
|
|
2e6c82c851 | ||
|
|
ee75dd37af | ||
|
|
4859dcda08 | ||
|
|
2e962e555d | ||
|
|
ab73e5acb2 | ||
|
|
4e3e5ce130 | ||
|
|
bb8eef3bf5 | ||
|
|
eee87ded29 | ||
|
|
e0f005bd96 | ||
|
|
2cacc372ad | ||
|
|
0b1b681655 | ||
|
|
deafd73306 | ||
|
|
317a5da120 | ||
|
|
071cefc511 | ||
|
|
32a5cc8aa3 | ||
|
|
c41378a085 | ||
|
|
6910e03ef4 | ||
|
|
5060a358db | ||
|
|
b3e9a957c4 | ||
|
|
f6dbfc2dac | ||
|
|
2966a34e63 | ||
|
|
50959951ae | ||
|
|
c2e1cf7bdb | ||
|
|
51ac7cc8be | ||
|
|
3144f1d1c2 | ||
|
|
a176e7b912 | ||
|
|
1198ec0f74 | ||
|
|
4104964e38 | ||
|
|
3bbd1edf06 | ||
|
|
41cc260b5c | ||
|
|
6cd5063c9b | ||
|
|
e544df6d01 | ||
|
|
f952d2383c | ||
|
|
8a29e147d3 | ||
|
|
8a19128e7f | ||
|
|
7dc9fbd8ff | ||
|
|
31a179e647 | ||
|
|
c3fdfcc4bd | ||
|
|
7ea8fae2da | ||
|
|
67ffa810d3 | ||
|
|
ba2a636dd2 | ||
|
|
d471336994 | ||
|
|
7e6482fdff | ||
|
|
a8eba93ffd | ||
|
|
4ffe595db6 | ||
|
|
885587e551 | ||
|
|
e986dc189e | ||
|
|
bccab41c8f | ||
|
|
79a0538ca0 | ||
|
|
e6b27d17e4 | ||
|
|
2a0012824a | ||
|
|
9d92be99ee | ||
|
|
6914831d30 | ||
|
|
19d83be6de | ||
|
|
ce7303bd0d | ||
|
|
4c3318ac86 | ||
|
|
db25fdeee1 | ||
|
|
732c3eee8b | ||
|
|
2b0d805b2f | ||
|
|
4faa94b2a3 | ||
|
|
331d11aee2 | ||
|
|
4d95d7d8c0 | ||
|
|
fd82623c74 | ||
|
|
4a32b2c814 | ||
|
|
45264005a4 | ||
|
|
253219dd16 | ||
|
|
b2feaf3ba9 | ||
|
|
6c5011ad68 | ||
|
|
c0f8b6b84c | ||
|
|
f71125d8f3 | ||
|
|
e674a025d8 | ||
|
|
dadc24876f | ||
|
|
98d4801b7e | ||
|
|
0e50bfb6eb | ||
|
|
a5aa286535 | ||
|
|
3caf025c3c | ||
|
|
c943c6c60a | ||
|
|
8c55c629cd | ||
|
|
0c38ebb63f | ||
|
|
75df85f598 | ||
|
|
59e99b2316 | ||
|
|
02f4dcbaf7 | ||
|
|
470dec5588 | ||
|
|
be1e37ddd0 | ||
|
|
fdc32601a9 | ||
|
|
d3b86858e1 | ||
|
|
9c20d9cb1f | ||
|
|
d2cda16378 | ||
|
|
2ab00d5b6f | ||
|
|
1b8a58cd07 | ||
|
|
0c3293045f | ||
|
|
4c4ce7e8d1 | ||
|
|
a0d4a3f2e8 | ||
|
|
26abe7e7d7 | ||
|
|
b9c86ed3a1 | ||
|
|
b7cff66a80 | ||
|
|
61a40d2860 | ||
|
|
80eb569366 | ||
|
|
54fe669d89 | ||
|
|
0953237e9e | ||
|
|
cf1a8599eb | ||
|
|
171132be12 | ||
|
|
43c95422b7 | ||
|
|
2662243641 | ||
|
|
060a35e091 | ||
|
|
de1132c2df | ||
|
|
f19edc9370 | ||
|
|
f1601c463b | ||
|
|
77b15cd530 | ||
|
|
a6479fe0d0 | ||
|
|
4ad4e27dc1 | ||
|
|
7370684985 | ||
|
|
5ae58e6a98 | ||
|
|
780ccb1932 | ||
|
|
6b4076be10 | ||
|
|
d7a04a15ae | ||
|
|
2ae43f8bdb | ||
|
|
d3ebc17a10 | ||
|
|
7a8680711e | ||
|
|
649e89e7af | ||
|
|
cb94d64395 | ||
|
|
2440dc2440 | ||
|
|
364a24c580 | ||
|
|
8f3e0dbd82 | ||
|
|
596234df26 | ||
|
|
c38aec50dc | ||
|
|
40915b5f98 | ||
|
|
a176613119 | ||
|
|
6c6de1ae7f | ||
|
|
edbd168dcf | ||
|
|
127858d582 | ||
|
|
baf90cfbdd | ||
|
|
1a5eeb9401 | ||
|
|
e0ae101ff4 | ||
|
|
8b4a07dfe8 | ||
|
|
db934e70cb | ||
|
|
b770048f05 | ||
|
|
27c53be209 | ||
|
|
d93c12b354 | ||
|
|
98d4a47efb | ||
|
|
8ab04c65b5 | ||
|
|
1b2dab1388 | ||
|
|
4f8dae7fa0 | ||
|
|
cdc23e32c4 | ||
|
|
20457e9e63 | ||
|
|
e63042af84 | ||
|
|
c35b4d3c1b | ||
|
|
64a83a5d64 | ||
|
|
01039d0b47 | ||
|
|
7c1e5a3cba | ||
|
|
038161527f | ||
|
|
b12b7a17e6 | ||
|
|
37cf23d5fe | ||
|
|
ed7fb4f6e3 | ||
|
|
5d4bd2fee6 | ||
|
|
aae5906311 | ||
|
|
4a7bafd011 | ||
|
|
626ebfe65d | ||
|
|
3cc75cd46d | ||
|
|
f809ee7b20 | ||
|
|
1295d8191c | ||
|
|
bc2adbfa77 | ||
|
|
9583dff176 | ||
|
|
5732b84a7b | ||
|
|
c0d27504ac | ||
|
|
3db1dd7bbb | ||
|
|
5392766c5e | ||
|
|
730b7dea37 | ||
|
|
02a13ce028 | ||
|
|
7884853098 | ||
|
|
e122ea8146 | ||
|
|
f500d2b9f4 | ||
|
|
79e53bf1f5 | ||
|
|
31de7ec094 | ||
|
|
2e4501187c | ||
|
|
4430c9bd74 | ||
|
|
cf8be85ff7 | ||
|
|
0759be1223 | ||
|
|
21f8ddcf9f | ||
|
|
37cba5ee34 | ||
|
|
ff642fd1ac | ||
|
|
647f1d9c8b | ||
|
|
d886195ee3 | ||
|
|
e2b8f4f89a | ||
|
|
1dcfe661e9 | ||
|
|
d6dd110781 | ||
|
|
a0f956c885 | ||
|
|
88bcafed97 | ||
|
|
6e4f15ab52 | ||
|
|
20cae1ff4d | ||
|
|
dcf621b822 | ||
|
|
eafa20032b | ||
|
|
7375e1a490 | ||
|
|
199d87ba84 | ||
|
|
b43975ebfc | ||
|
|
fe7314c978 | ||
|
|
d4eb8e59a6 | ||
|
|
8ee00907b7 | ||
|
|
25fddc3c71 | ||
|
|
c78b733850 | ||
|
|
a57c83125e | ||
|
|
247b59985f | ||
|
|
7470b8b6d3 | ||
|
|
776d37b7aa | ||
|
|
8f532f8468 | ||
|
|
472963fe2d | ||
|
|
6a9b62ab9a | ||
|
|
9ac8aa2969 | ||
|
|
838bd2c794 | ||
|
|
b2bbe432e0 | ||
|
|
b3d8042452 | ||
|
|
0c758a7fdc | ||
|
|
85cb1d1c92 | ||
|
|
2cd2e8894d | ||
|
|
abb58379b3 | ||
|
|
4f48e8b190 | ||
|
|
2b5cbb5e74 | ||
|
|
23dd140921 | ||
|
|
8c8d7bda64 | ||
|
|
a6e246948a | ||
|
|
c49ba735a0 | ||
|
|
1a33c598e8 | ||
|
|
a4bbdb49de | ||
|
|
cf3846fbfd | ||
|
|
d46943eedf | ||
|
|
3bc17bd50a | ||
|
|
48a159f4c8 | ||
|
|
3d1bcffdc5 | ||
|
|
45fa0f94d2 | ||
|
|
ed16b7de4a | ||
|
|
f2ec03c7ec | ||
|
|
11db87f1e6 | ||
|
|
a1feaf33e0 | ||
|
|
53a99e3f79 | ||
|
|
e7f04f55c2 | ||
|
|
6653ea12b7 | ||
|
|
a28cef5b98 | ||
|
|
78a28fbdb3 | ||
|
|
bf8bbbdcb0 | ||
|
|
83ad83b135 | ||
|
|
dbd4f55981 | ||
|
|
5f5d7172ee | ||
|
|
fbd4557b44 | ||
|
|
5d55a55754 | ||
|
|
84032aec33 | ||
|
|
a372d8902e | ||
|
|
c38c62e4c3 | ||
|
|
8aceff7480 | ||
|
|
736c450161 | ||
|
|
3b63a3d308 | ||
|
|
4f56174c8f | ||
|
|
4d2eb324f1 | ||
|
|
3f2ab8ddcb | ||
|
|
fd8f863c5b | ||
|
|
246f1d7df0 | ||
|
|
ccacda9bf5 | ||
|
|
5494d63878 | ||
|
|
c32b9812a7 | ||
|
|
9eb9898b61 | ||
|
|
834e05999f | ||
|
|
b4c37d9906 | ||
|
|
9326b450d7 | ||
|
|
019ee8b1ba | ||
|
|
f043645397 | ||
|
|
3b173f0b3e | ||
|
|
f36c06389d | ||
|
|
d3a0b44247 | ||
|
|
e4d3a98aa8 | ||
|
|
f685682214 | ||
|
|
1c6323315b | ||
|
|
1ff4839be1 | ||
|
|
558e5bb340 | ||
|
|
48a9d208e6 | ||
|
|
f29e1f8c45 | ||
|
|
5d2bc88bb9 | ||
|
|
298fdb1191 | ||
|
|
59b34688ea | ||
|
|
5ce0bb6e4a | ||
|
|
487b1ab182 | ||
|
|
5c144a8ba3 | ||
|
|
ad344356df | ||
|
|
a55c65374d | ||
|
|
28447a9d43 | ||
|
|
0c03550c62 | ||
|
|
6d9a84803f | ||
|
|
03b0e4e2bb | ||
|
|
a00e9a6f5e | ||
|
|
ba17f8fde9 | ||
|
|
01d35456bd | ||
|
|
672b8c48ac | ||
|
|
ac1a357740 | ||
|
|
504f8d09a6 | ||
|
|
89ce7c23c9 | ||
|
|
a5d99b1eb5 | ||
|
|
800d193acb | ||
|
|
7a1d12be76 | ||
|
|
1b9c95e801 | ||
|
|
9f44815470 | ||
|
|
ca38239bce | ||
|
|
d9c22de6b8 | ||
|
|
49a3c84fc5 | ||
|
|
5e0c28438b | ||
|
|
a6dc801bc4 | ||
|
|
22009d1b71 | ||
|
|
50f39dc40e |
170
.editorconfig
Normal file
170
.editorconfig
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
tab_width = 4
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = crlf
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.cs]
|
||||||
|
dotnet_hide_advanced_members = true
|
||||||
|
dotnet_member_insertion_location = with_other_members_of_the_same_kind
|
||||||
|
dotnet_property_generation_behavior = prefer_throwing_properties
|
||||||
|
dotnet_search_reference_assemblies = true
|
||||||
|
dotnet_separate_import_directive_groups = false:warning
|
||||||
|
dotnet_sort_system_directives_first = true:warning
|
||||||
|
file_header_template = unset
|
||||||
|
|
||||||
|
dotnet_style_qualification_for_event = false:warning
|
||||||
|
dotnet_style_qualification_for_field = false:warning
|
||||||
|
dotnet_style_qualification_for_method = false:warning
|
||||||
|
dotnet_style_qualification_for_property = false:warning
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true:warning
|
||||||
|
dotnet_style_predefined_type_for_member_access = true:warning
|
||||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
|
||||||
|
dotnet_style_parentheses_in_other_operators = always_for_clarity:warning
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
|
||||||
|
dotnet_style_require_accessibility_modifiers = always:warning
|
||||||
|
dotnet_prefer_system_hash_code = true:warning
|
||||||
|
dotnet_style_coalesce_expression = true:warning
|
||||||
|
dotnet_style_collection_initializer = false:warning
|
||||||
|
dotnet_style_explicit_tuple_names = true:warning
|
||||||
|
dotnet_style_namespace_match_folder = true:warning
|
||||||
|
dotnet_style_null_propagation = true:warning
|
||||||
|
dotnet_style_object_initializer = true:warning
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
dotnet_style_prefer_auto_properties = true:warning
|
||||||
|
dotnet_style_prefer_collection_expression = false:warning
|
||||||
|
dotnet_style_prefer_compound_assignment = true:warning
|
||||||
|
dotnet_style_prefer_conditional_expression_over_assignment = false:warning
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = false:warning
|
||||||
|
dotnet_style_prefer_foreach_explicit_cast_in_source = always:warning
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning
|
||||||
|
dotnet_style_prefer_inferred_tuple_names = true:warning
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true:warning
|
||||||
|
dotnet_style_prefer_simplified_interpolation = true:warning
|
||||||
|
dotnet_style_readonly_field = true:warning
|
||||||
|
dotnet_code_quality_unused_parameters = all:warning
|
||||||
|
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||||
|
dotnet_style_allow_multiple_blank_lines_experimental = false:warning
|
||||||
|
dotnet_style_allow_statement_immediately_after_block_experimental = true:warning
|
||||||
|
|
||||||
|
csharp_style_var_elsewhere = true:warning
|
||||||
|
csharp_style_var_for_built_in_types = true:warning
|
||||||
|
csharp_style_var_when_type_is_apparent = true:warning
|
||||||
|
csharp_style_expression_bodied_accessors = when_on_single_line:warning
|
||||||
|
csharp_style_expression_bodied_constructors = false:warning
|
||||||
|
csharp_style_expression_bodied_indexers = when_on_single_line:warning
|
||||||
|
csharp_style_expression_bodied_lambdas = when_on_single_line:warning
|
||||||
|
csharp_style_expression_bodied_local_functions = false:warning
|
||||||
|
csharp_style_expression_bodied_methods = false:warning
|
||||||
|
csharp_style_expression_bodied_operators = false:warning
|
||||||
|
csharp_style_expression_bodied_properties = when_on_single_line:warning
|
||||||
|
csharp_style_pattern_matching_over_as_with_null_check = true:warning
|
||||||
|
csharp_style_pattern_matching_over_is_with_cast_check = true:warning
|
||||||
|
csharp_style_prefer_extended_property_pattern = true:warning
|
||||||
|
csharp_style_prefer_not_pattern = true:warning
|
||||||
|
csharp_style_prefer_pattern_matching = true:warning
|
||||||
|
csharp_style_prefer_switch_expression = false:warning
|
||||||
|
csharp_style_conditional_delegate_call = true:warning
|
||||||
|
csharp_prefer_static_anonymous_function = true:warning
|
||||||
|
csharp_prefer_static_local_function = true:warning
|
||||||
|
csharp_preferred_modifier_order = public,internal,private,protected,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:warning
|
||||||
|
csharp_style_prefer_readonly_struct = true:warning
|
||||||
|
csharp_style_prefer_readonly_struct_member = true:warning
|
||||||
|
csharp_prefer_braces = true:warning
|
||||||
|
csharp_prefer_simple_using_statement = true:warning
|
||||||
|
csharp_prefer_system_threading_lock = true:warning
|
||||||
|
csharp_style_namespace_declarations = file_scoped:warning
|
||||||
|
csharp_style_prefer_method_group_conversion = true:warning
|
||||||
|
csharp_style_prefer_primary_constructors = true:warning
|
||||||
|
csharp_style_prefer_top_level_statements = false:warning
|
||||||
|
csharp_prefer_simple_default_expression = true:warning
|
||||||
|
csharp_style_deconstructed_variable_declaration = true:warning
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
|
||||||
|
csharp_style_inlined_variable_declaration = true:warning
|
||||||
|
csharp_style_prefer_index_operator = false:warning
|
||||||
|
csharp_style_prefer_local_over_anonymous_function = true:warning
|
||||||
|
csharp_style_prefer_null_check_over_type_check = true:warning
|
||||||
|
csharp_style_prefer_range_operator = false:warning
|
||||||
|
csharp_style_prefer_tuple_swap = true:warning
|
||||||
|
csharp_style_prefer_utf8_string_literals = true:warning
|
||||||
|
csharp_style_throw_expression = true:warning
|
||||||
|
csharp_style_unused_value_assignment_preference = discard_variable:warning
|
||||||
|
csharp_style_unused_value_expression_statement_preference = discard_variable:warning
|
||||||
|
csharp_using_directive_placement = outside_namespace:warning
|
||||||
|
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:warning
|
||||||
|
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:warning
|
||||||
|
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false:warning
|
||||||
|
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false:warning
|
||||||
|
csharp_style_allow_embedded_statements_on_same_line_experimental = false:warning
|
||||||
|
|
||||||
|
csharp_new_line_before_catch = true
|
||||||
|
csharp_new_line_before_else = true
|
||||||
|
csharp_new_line_before_finally = true
|
||||||
|
csharp_new_line_before_members_in_anonymous_types = true
|
||||||
|
csharp_new_line_before_members_in_object_initializers = true
|
||||||
|
csharp_new_line_before_open_brace = all
|
||||||
|
csharp_new_line_between_query_expression_clauses = true
|
||||||
|
csharp_indent_block_contents = true
|
||||||
|
csharp_indent_braces = false
|
||||||
|
csharp_indent_case_contents = true
|
||||||
|
csharp_indent_case_contents_when_block = true
|
||||||
|
csharp_indent_labels = no_change
|
||||||
|
csharp_indent_switch_labels = true
|
||||||
|
csharp_space_after_cast = false
|
||||||
|
csharp_space_after_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_after_comma = true
|
||||||
|
csharp_space_after_dot = false
|
||||||
|
csharp_space_after_keywords_in_control_flow_statements = true
|
||||||
|
csharp_space_after_semicolon_in_for_statement = true
|
||||||
|
csharp_space_around_binary_operators = before_and_after
|
||||||
|
csharp_space_around_declaration_statements = false:warning
|
||||||
|
csharp_space_before_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_before_comma = false
|
||||||
|
csharp_space_before_dot = false
|
||||||
|
csharp_space_before_open_square_brackets = false
|
||||||
|
csharp_space_before_semicolon_in_for_statement = false
|
||||||
|
csharp_space_between_empty_square_brackets = false
|
||||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||||
|
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_parentheses = false
|
||||||
|
csharp_space_between_square_brackets = false
|
||||||
|
csharp_preserve_single_line_blocks = true
|
||||||
|
csharp_preserve_single_line_statements = false
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_pascal.severity = warning
|
||||||
|
dotnet_naming_rule.interface_should_be_pascal.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_pascal.style = pascal
|
||||||
|
dotnet_naming_rule.types_should_be_pascal.severity = warning
|
||||||
|
dotnet_naming_rule.types_should_be_pascal.symbols = types
|
||||||
|
dotnet_naming_rule.types_should_be_pascal.style = pascal
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal.severity = warning
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal.symbols = non_field_members
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal.style = pascal
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = *
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.types.applicable_accessibilities = *
|
||||||
|
dotnet_naming_symbols.types.required_modifiers =
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = *
|
||||||
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
dotnet_naming_style.pascal.required_prefix =
|
||||||
|
dotnet_naming_style.pascal.required_suffix =
|
||||||
|
dotnet_naming_style.pascal.word_separator =
|
||||||
|
dotnet_naming_style.pascal.capitalization = pascal_case
|
||||||
0
v2rayN/.gitattributes → .gitattributes
vendored
0
v2rayN/.gitattributes → .gitattributes
vendored
7
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
7
.github/ISSUE_TEMPLATE/01_bug_report.yml
vendored
@@ -3,6 +3,13 @@ description: 在提出问题前请先自行排除服务器端问题和升级到
|
|||||||
title: "[Bug]: "
|
title: "[Bug]: "
|
||||||
labels: ["bug"]
|
labels: ["bug"]
|
||||||
body:
|
body:
|
||||||
|
- type: input
|
||||||
|
id: "os-version"
|
||||||
|
attributes:
|
||||||
|
label: "操作系统和版本"
|
||||||
|
description: "操作系统和版本"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
id: "expectation"
|
id: "expectation"
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
9
.github/dependabot.yml
vendored
9
.github/dependabot.yml
vendored
@@ -1,10 +1,11 @@
|
|||||||
# Set update schedule for GitHub Actions
|
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
|
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
# Check for updates to GitHub Actions every daily
|
interval: "daily"
|
||||||
|
|
||||||
|
- package-ecosystem: "nuget"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
|||||||
69
.github/workflows/build-all.yml
vendored
Normal file
69
.github/workflows/build-all.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
name: release all platforms
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_tag:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Trigger build windows
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
curl -X POST \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||||
|
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows.yml/dispatches \
|
||||||
|
-d "{
|
||||||
|
\"ref\": \"master\",
|
||||||
|
\"inputs\": {
|
||||||
|
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
- name: Trigger build linux
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
curl -X POST \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||||
|
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-linux.yml/dispatches \
|
||||||
|
-d "{
|
||||||
|
\"ref\": \"master\",
|
||||||
|
\"inputs\": {
|
||||||
|
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
- name: Trigger build osx
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
curl -X POST \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||||
|
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-osx.yml/dispatches \
|
||||||
|
-d "{
|
||||||
|
\"ref\": \"master\",
|
||||||
|
\"inputs\": {
|
||||||
|
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
|
||||||
|
- name: Trigger build windows desktop
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
curl -X POST \
|
||||||
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
|
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||||
|
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build-windows-desktop.yml/dispatches \
|
||||||
|
-d "{
|
||||||
|
\"ref\": \"master\",
|
||||||
|
\"inputs\": {
|
||||||
|
\"release_tag\": \"${{ github.event.inputs.release_tag }}\"
|
||||||
|
}
|
||||||
|
}"
|
||||||
101
.github/workflows/build-linux.yml
vendored
Normal file
101
.github/workflows/build-linux.yml
vendored
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
name: release Linux
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_tag:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
OutputArch: "linux-64"
|
||||||
|
OutputArchArm: "linux-arm64"
|
||||||
|
OutputPath64: "${{ github.workspace }}/v2rayN/Release/linux-64"
|
||||||
|
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/linux-arm64"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
configuration: [Release]
|
||||||
|
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.2.2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
fetch-depth: '0'
|
||||||
|
|
||||||
|
- name: Setup
|
||||||
|
uses: actions/setup-dotnet@v4.3.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd v2rayN
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-x64 --self-contained=true -o $OutputPath64
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r linux-arm64 --self-contained=true -o $OutputPathArm64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r linux-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4.6.1
|
||||||
|
with:
|
||||||
|
name: v2rayN-linux
|
||||||
|
path: |
|
||||||
|
${{ github.workspace }}/v2rayN/Release/linux*
|
||||||
|
|
||||||
|
# release debian package
|
||||||
|
- name: Package debian
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
chmod 755 package-debian.sh
|
||||||
|
./package-debian.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
||||||
|
./package-debian.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
||||||
|
|
||||||
|
- name: Upload deb to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.deb
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
|
|
||||||
|
- name: Package AppImage
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
chmod a+x package-appimage.sh
|
||||||
|
./package-appimage.sh
|
||||||
|
|
||||||
|
- name: Upload AppImage to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.AppImage
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
|
|
||||||
|
# release zip archive
|
||||||
|
- name: Package release zip archive
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
chmod 755 package-release-zip.sh
|
||||||
|
./package-release-zip.sh $OutputArch $OutputPath64
|
||||||
|
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||||
|
|
||||||
|
- name: Upload zip archive to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.zip
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
87
.github/workflows/build-osx.yml
vendored
Normal file
87
.github/workflows/build-osx.yml
vendored
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
name: release macOS
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_tag:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
OutputArch: "macos-64"
|
||||||
|
OutputArchArm: "macos-arm64"
|
||||||
|
OutputPath64: "${{ github.workspace }}/v2rayN/Release/macos-64"
|
||||||
|
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/macos-arm64"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
configuration: [Release]
|
||||||
|
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.2.2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
fetch-depth: '0'
|
||||||
|
|
||||||
|
- name: Setup
|
||||||
|
uses: actions/setup-dotnet@v4.3.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd v2rayN
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-x64 --self-contained=true -o $OutputPath64
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r osx-arm64 --self-contained=true -o $OutputPathArm64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-x64 --self-contained=true -p:PublishTrimmed=true -o $OutputPath64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r osx-arm64 --self-contained=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4.6.1
|
||||||
|
with:
|
||||||
|
name: v2rayN-macos
|
||||||
|
path: |
|
||||||
|
${{ github.workspace }}/v2rayN/Release/macos*
|
||||||
|
|
||||||
|
# release osx package
|
||||||
|
- name: Package osx
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
brew install create-dmg
|
||||||
|
chmod 755 package-osx.sh
|
||||||
|
./package-osx.sh $OutputArch $OutputPath64 ${{ github.event.inputs.release_tag }}
|
||||||
|
./package-osx.sh $OutputArchArm $OutputPathArm64 ${{ github.event.inputs.release_tag }}
|
||||||
|
|
||||||
|
- name: Upload dmg to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.dmg
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
|
|
||||||
|
# release zip archive
|
||||||
|
- name: Package release zip archive
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
chmod 755 package-release-zip.sh
|
||||||
|
./package-release-zip.sh $OutputArch $OutputPath64
|
||||||
|
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||||
|
|
||||||
|
- name: Upload zip archive to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.zip
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
71
.github/workflows/build-windows-desktop.yml
vendored
Normal file
71
.github/workflows/build-windows-desktop.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
name: release Windows desktop (Avalonia UI)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_tag:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
OutputArch: "windows-64"
|
||||||
|
OutputArchArm: "windows-arm64"
|
||||||
|
OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64"
|
||||||
|
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
configuration: [Release]
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.2.2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
fetch-depth: '0'
|
||||||
|
|
||||||
|
- name: Setup
|
||||||
|
uses: actions/setup-dotnet@v4.3.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd v2rayN
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||||
|
dotnet publish ./v2rayN.Desktop/v2rayN.Desktop.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPathArm64
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4.6.1
|
||||||
|
with:
|
||||||
|
name: v2rayN-windows-desktop
|
||||||
|
path: |
|
||||||
|
${{ github.workspace }}/v2rayN/Release/windows*
|
||||||
|
|
||||||
|
# release zip archive
|
||||||
|
- name: Package release zip archive
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
chmod 755 package-release-zip.sh
|
||||||
|
./package-release-zip.sh $OutputArch $OutputPath64
|
||||||
|
mv "v2rayN-${OutputArch}.zip" "v2rayN-${OutputArch}-desktop.zip"
|
||||||
|
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||||
|
mv "v2rayN-${OutputArchArm}.zip" "v2rayN-${OutputArchArm}-desktop.zip"
|
||||||
|
|
||||||
|
- name: Upload zip archive to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.zip
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
71
.github/workflows/build-windows.yml
vendored
Normal file
71
.github/workflows/build-windows.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
name: release Windows
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
release_tag:
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
env:
|
||||||
|
OutputArch: "windows-64"
|
||||||
|
OutputArchArm: "windows-arm64"
|
||||||
|
OutputPath64: "${{ github.workspace }}/v2rayN/Release/windows-64"
|
||||||
|
OutputPathArm64: "${{ github.workspace }}/v2rayN/Release/windows-arm64"
|
||||||
|
OutputPath64Sc: "${{ github.workspace }}/v2rayN/Release/windows-64-SelfContained"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
configuration: [Release]
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4.2.2
|
||||||
|
|
||||||
|
- name: Setup
|
||||||
|
uses: actions/setup-dotnet@v4.3.0
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd v2rayN
|
||||||
|
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||||
|
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||||
|
dotnet publish ./v2rayN/v2rayN.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -o $OutputPath64Sc
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPath64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-arm64 --self-contained=false -p:EnableWindowsTargeting=true -o $OutputPathArm64
|
||||||
|
dotnet publish ./AmazTool/AmazTool.csproj -c Release -r win-x64 --self-contained=true -p:EnableWindowsTargeting=true -p:PublishTrimmed=true -o $OutputPath64Sc
|
||||||
|
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4.6.1
|
||||||
|
with:
|
||||||
|
name: v2rayN-windows
|
||||||
|
path: |
|
||||||
|
${{ github.workspace }}/v2rayN/Release/windows*
|
||||||
|
|
||||||
|
# release zip archive
|
||||||
|
- name: Package release zip archive
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
run: |
|
||||||
|
chmod 755 package-release-zip.sh
|
||||||
|
./package-release-zip.sh $OutputArch $OutputPath64
|
||||||
|
./package-release-zip.sh $OutputArchArm $OutputPathArm64
|
||||||
|
./package-release-zip.sh "windows-64-SelfContained" $OutputPath64Sc
|
||||||
|
|
||||||
|
- name: Upload zip archive to release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
if: github.event.inputs.release_tag != ''
|
||||||
|
with:
|
||||||
|
file: ${{ github.workspace }}/v2rayN*.zip
|
||||||
|
tag: ${{ github.event.inputs.release_tag }}
|
||||||
|
file_glob: true
|
||||||
|
prerelease: true
|
||||||
60
.github/workflows/build.yml
vendored
60
.github/workflows/build.yml
vendored
@@ -1,60 +0,0 @@
|
|||||||
name: release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "master" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "master" ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
configuration: [Release]
|
|
||||||
|
|
||||||
runs-on: windows-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# - name: 删除工作流运行
|
|
||||||
# uses: Mattraks/delete-workflow-runs@v2
|
|
||||||
# with:
|
|
||||||
# token: ${{ github.token }}
|
|
||||||
# repository: ${{ github.repository }}
|
|
||||||
# retain_days: 0
|
|
||||||
# keep_minimum_runs: 1
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: cd v2rayN &&
|
|
||||||
.\build.ps1
|
|
||||||
|
|
||||||
# - name: Package
|
|
||||||
# shell: pwsh
|
|
||||||
# run: |
|
|
||||||
# 7z a -mx9 ..\v2rayN.7z $env:Wap_Project_Directory
|
|
||||||
|
|
||||||
- name: Upload build artifacts
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: v2rayN
|
|
||||||
path: |
|
|
||||||
.\v2rayN\v2rayN.zip
|
|
||||||
|
|
||||||
# - name: Release
|
|
||||||
# uses: softprops/action-gh-release@v1
|
|
||||||
# env:
|
|
||||||
# GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
|
|
||||||
# with:
|
|
||||||
# prerelease: ${{ contains(github.ref, '-') }}
|
|
||||||
# draft: false
|
|
||||||
# files: |
|
|
||||||
# .\v2rayN\v2rayN.zip
|
|
||||||
# body: |
|
|
||||||
# [](https://t.me/netch_channel) [](https://t.me/netch_group)
|
|
||||||
# ## Changelogs
|
|
||||||
# * This is an automated deployment of GitHub Actions, the change log should be updated manually soon
|
|
||||||
|
|
||||||
# ## 更新日志
|
|
||||||
# * 这是 GitHub Actions 自动化部署,更新日志应该很快会手动更新
|
|
||||||
31
.github/workflows/winget-publish.yml
vendored
Normal file
31
.github/workflows/winget-publish.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
name: WinGet submission on release
|
||||||
|
# based off of https://github.com/nushell/nushell/blob/main/.github/workflows/winget-submission.yml
|
||||||
|
# inspired by https://github.com/microsoft/PowerToys/blob/main/.github/workflows/package-submissions.yml
|
||||||
|
# Modified by @MerrickZ https://github.com/anpho
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
winget:
|
||||||
|
name: Publish winget package
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Submit v2ray package to Windows Package Manager Community Repository
|
||||||
|
run: |
|
||||||
|
|
||||||
|
$wingetPackage = "2dust.v2rayN"
|
||||||
|
$gitToken = "${{ secrets.PT_WINGET }}"
|
||||||
|
|
||||||
|
$github = Invoke-RestMethod -uri "https://api.github.com/repos/2dust/v2rayN/releases"
|
||||||
|
|
||||||
|
$targetRelease = $github | Where-Object -Property prerelease -match 'False' | Select -First 1
|
||||||
|
$installerUrl = $targetRelease | Select -ExpandProperty assets -First 1 | Where-Object -Property name -match 'v2rayN-windows-64\.zip*' | Select -ExpandProperty browser_download_url
|
||||||
|
|
||||||
|
$ver = $targetRelease.tag_name
|
||||||
|
|
||||||
|
# getting latest wingetcreate file
|
||||||
|
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
|
||||||
|
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$installerUrl|x64" -t $gitToken
|
||||||
415
.gitignore
vendored
415
.gitignore
vendored
@@ -1,19 +1,400 @@
|
|||||||
################################################################################
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
|
## files generated by popular Visual Studio add-ons.
|
||||||
################################################################################
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
/v2rayN/.vs/
|
# User-specific files
|
||||||
/v2rayN/v2rayN/bin/Debug/app.publish
|
*.rsuser
|
||||||
/v2rayN/v2rayN/bin/Debug
|
*.suo
|
||||||
/v2rayN/v2rayN/bin/Release
|
|
||||||
/v2rayN/v2rayN/obj/
|
|
||||||
/v2rayN/.vs/v2rayN/DesignTimeBuild
|
|
||||||
/v2rayN/packages
|
|
||||||
.vs/ProjectSettings.json
|
|
||||||
.vs/slnx.sqlite
|
|
||||||
.vs/VSWorkspaceState.json
|
|
||||||
/v2rayN/v2rayUpgrade/bin/Debug
|
|
||||||
/v2rayN/v2rayUpgrade/bin/Release
|
|
||||||
/v2rayN/v2rayUpgrade/obj/
|
|
||||||
*.user
|
*.user
|
||||||
/.vs/v2rayN
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
# but not Directory.Build.rsp, as it configures directory-level build defaults
|
||||||
|
!Directory.Build.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.tlog
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "v2rayN/GlobalHotKeys"]
|
||||||
|
path = v2rayN/GlobalHotKeys
|
||||||
|
url = https://github.com/2dust/GlobalHotKeys
|
||||||
17
README.md
17
README.md
@@ -1,5 +1,5 @@
|
|||||||
# v2rayN
|
# v2rayN
|
||||||
A GUI client for Windows and Linux, support [Xray core](https://github.com/XTLS/Xray-core) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
A GUI client for Windows, Linux and macOS, support [Xray](https://github.com/XTLS/Xray-core) and [sing-box](https://github.com/SagerNet/sing-box/releases) and [others](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
||||||
|
|
||||||
|
|
||||||
[](https://github.com/2dust/v2rayN/commits/master)
|
[](https://github.com/2dust/v2rayN/commits/master)
|
||||||
@@ -9,21 +9,8 @@ A GUI client for Windows and Linux, support [Xray core](https://github.com/XTLS/
|
|||||||
|
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
Check [Release files introduction](https://github.com/2dust/v2rayN/wiki/Release-files-introduction) and select the version you need to download
|
|
||||||
### Windows
|
|
||||||
- Run `v2rayN.exe`
|
|
||||||
### Linux
|
|
||||||
- `chmod +x v2rayN` Run `./v2rayN`
|
|
||||||
```
|
|
||||||
Debian 9+
|
|
||||||
Ubuntu 16.04+
|
|
||||||
Fedora 30+
|
|
||||||
```
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
- [Microsoft .NET 8.0 Desktop Runtime ](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
|
|
||||||
- [Supported cores](https://github.com/2dust/v2rayN/wiki/List-of-supported-cores)
|
|
||||||
|
|
||||||
|
Read the [Wiki](https://github.com/2dust/v2rayN/wiki) for details.
|
||||||
|
|
||||||
## Telegram Channel
|
## Telegram Channel
|
||||||
[github_2dust](https://t.me/github_2dust)
|
[github_2dust](https://t.me/github_2dust)
|
||||||
|
|||||||
14
package-appimage.sh
Normal file
14
package-appimage.sh
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
sudo apt update -y
|
||||||
|
sudo apt install -y libfuse2
|
||||||
|
wget -O pkg2appimage https://github.com/AppImageCommunity/pkg2appimage/releases/download/continuous/pkg2appimage-1eceb30-x86_64.AppImage
|
||||||
|
chmod a+x pkg2appimage
|
||||||
|
export AppImageOutputArch=$OutputArch
|
||||||
|
export OutputPath=$OutputPath64
|
||||||
|
./pkg2appimage ./pkg2appimage.yml
|
||||||
|
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage
|
||||||
|
export AppImageOutputArch=$OutputArchArm
|
||||||
|
export OutputPath=$OutputPathArm64
|
||||||
|
./pkg2appimage ./pkg2appimage.yml
|
||||||
|
mv out/*.AppImage v2rayN-${AppImageOutputArch}.AppImage
|
||||||
58
package-debian.sh
Normal file
58
package-debian.sh
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
Arch="$1"
|
||||||
|
OutputPath="$2"
|
||||||
|
Version="$3"
|
||||||
|
|
||||||
|
FileName="v2rayN-${Arch}.zip"
|
||||||
|
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
||||||
|
7z x $FileName
|
||||||
|
cp -rf v2rayN-${Arch}/* $OutputPath
|
||||||
|
|
||||||
|
PackagePath="v2rayN-Package-${Arch}"
|
||||||
|
mkdir -p "${PackagePath}/DEBIAN"
|
||||||
|
mkdir -p "${PackagePath}/opt"
|
||||||
|
cp -rf $OutputPath "${PackagePath}/opt/v2rayN"
|
||||||
|
echo "When this file exists, app will not store configs under this folder" > "${PackagePath}/opt/v2rayN/NotStoreConfigHere.txt"
|
||||||
|
|
||||||
|
if [ $Arch = "linux-64" ]; then
|
||||||
|
Arch2="amd64"
|
||||||
|
else
|
||||||
|
Arch2="arm64"
|
||||||
|
fi
|
||||||
|
echo $Arch2
|
||||||
|
|
||||||
|
# basic
|
||||||
|
cat >"${PackagePath}/DEBIAN/control" <<-EOF
|
||||||
|
Package: v2rayN
|
||||||
|
Version: $Version
|
||||||
|
Architecture: $Arch2
|
||||||
|
Maintainer: https://github.com/2dust/v2rayN
|
||||||
|
Description: A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >"${PackagePath}/DEBIAN/postinst" <<-EOF
|
||||||
|
if [ ! -s /usr/share/applications/v2rayN.desktop ]; then
|
||||||
|
cat >/usr/share/applications/v2rayN.desktop<<-END
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=v2rayN
|
||||||
|
Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||||
|
Exec=/opt/v2rayN/v2rayN
|
||||||
|
Icon=/opt/v2rayN/v2rayN.png
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
Categories=Network;Application;
|
||||||
|
END
|
||||||
|
fi
|
||||||
|
|
||||||
|
update-desktop-database
|
||||||
|
EOF
|
||||||
|
|
||||||
|
sudo chmod 0755 "${PackagePath}/DEBIAN/postinst"
|
||||||
|
sudo chmod 0755 "${PackagePath}/opt/v2rayN/v2rayN"
|
||||||
|
sudo chmod 0755 "${PackagePath}/opt/v2rayN/AmazTool"
|
||||||
|
|
||||||
|
# desktop && PATH
|
||||||
|
|
||||||
|
sudo dpkg-deb -Zxz --build $PackagePath
|
||||||
|
sudo mv "${PackagePath}.deb" "v2rayN-${Arch}.deb"
|
||||||
58
package-osx.sh
Executable file
58
package-osx.sh
Executable file
@@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
Arch="$1"
|
||||||
|
OutputPath="$2"
|
||||||
|
Version="$3"
|
||||||
|
|
||||||
|
FileName="v2rayN-${Arch}.zip"
|
||||||
|
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
||||||
|
7z x $FileName
|
||||||
|
cp -rf v2rayN-${Arch}/* $OutputPath
|
||||||
|
|
||||||
|
PackagePath="v2rayN-Package-${Arch}"
|
||||||
|
mkdir -p "$PackagePath/v2rayN.app/Contents/Resources"
|
||||||
|
cp -rf "$OutputPath" "$PackagePath/v2rayN.app/Contents/MacOS"
|
||||||
|
cp -f "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN.icns" "$PackagePath/v2rayN.app/Contents/Resources/AppIcon.icns"
|
||||||
|
echo "When this file exists, app will not store configs under this folder" > "$PackagePath/v2rayN.app/Contents/MacOS/NotStoreConfigHere.txt"
|
||||||
|
chmod +x "$PackagePath/v2rayN.app/Contents/MacOS/v2rayN"
|
||||||
|
|
||||||
|
cat >"$PackagePath/v2rayN.app/Contents/Info.plist" <<-EOF
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>English</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>v2rayN</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>v2rayN</string>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>AppIcon</string>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>AppIcon</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>2dust.v2rayN</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>v2rayN</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${Version}</string>
|
||||||
|
<key>CSResourcesFileMapped</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSHighResolutionCapable</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
create-dmg \
|
||||||
|
--volname "v2rayN Installer" \
|
||||||
|
--window-size 700 420 \
|
||||||
|
--icon-size 100 \
|
||||||
|
--icon "v2rayN.app" 160 185 \
|
||||||
|
--hide-extension "v2rayN.app" \
|
||||||
|
--app-drop-link 500 185 \
|
||||||
|
"v2rayN-${Arch}.dmg" \
|
||||||
|
"$PackagePath/v2rayN.app"
|
||||||
15
package-release-zip.sh
Normal file
15
package-release-zip.sh
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
Arch="$1"
|
||||||
|
OutputPath="$2"
|
||||||
|
|
||||||
|
OutputArch="v2rayN-${Arch}"
|
||||||
|
FileName="v2rayN-${Arch}.zip"
|
||||||
|
|
||||||
|
wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/$FileName"
|
||||||
|
|
||||||
|
ZipPath64="./$OutputArch"
|
||||||
|
mkdir $ZipPath64
|
||||||
|
|
||||||
|
cp -rf $OutputPath "$ZipPath64/$OutputArch"
|
||||||
|
7z a -tZip $FileName "$ZipPath64/$OutputArch" -mx1
|
||||||
37
pkg2appimage.yml
Normal file
37
pkg2appimage.yml
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
app: v2rayN
|
||||||
|
binpatch: true
|
||||||
|
|
||||||
|
ingredients:
|
||||||
|
script:
|
||||||
|
- export FileName="v2rayN-${AppImageOutputArch}.zip"
|
||||||
|
- wget -nv -O $FileName "https://github.com/2dust/v2rayN-core-bin/raw/refs/heads/master/${FileName}"
|
||||||
|
- 7z x $FileName -aoa
|
||||||
|
- cp -rf v2rayN-${AppImageOutputArch}/* $OutputPath
|
||||||
|
|
||||||
|
script:
|
||||||
|
- mkdir -p usr/bin usr/lib
|
||||||
|
- cp -rf $OutputPath usr/lib/v2rayN
|
||||||
|
- echo "When this file exists, app will not store configs under this folder" > usr/lib/v2rayN/NotStoreConfigHere.txt
|
||||||
|
- ln -sf usr/lib/v2rayN/v2rayN usr/bin/v2rayN
|
||||||
|
- chmod a+x usr/lib/v2rayN/v2rayN
|
||||||
|
- find usr -type f -exec sh -c 'file "{}" | grep -qi "executable" && chmod +x "{}"' \;
|
||||||
|
- install -Dm644 usr/lib/v2rayN/v2rayN.png v2rayN.png
|
||||||
|
- install -Dm644 usr/lib/v2rayN/v2rayN.png usr/share/pixmaps/v2rayN.png
|
||||||
|
- cat > v2rayN.desktop <<EOF
|
||||||
|
- [Desktop Entry]
|
||||||
|
- Name=v2rayN
|
||||||
|
- Comment=A GUI client for Windows and Linux, support Xray core and sing-box-core and others
|
||||||
|
- Exec=v2rayN
|
||||||
|
- Icon=v2rayN
|
||||||
|
- Terminal=false
|
||||||
|
- Type=Application
|
||||||
|
- Categories=Network;
|
||||||
|
- EOF
|
||||||
|
- install -Dm644 v2rayN.desktop usr/share/applications/v2rayN.desktop
|
||||||
|
- cat > AppRun <<\EOF
|
||||||
|
- #!/bin/sh
|
||||||
|
- HERE="$(dirname "$(readlink -f "${0}")")"
|
||||||
|
- cd ${HERE}/usr/lib/v2rayN
|
||||||
|
- exec ${HERE}/usr/lib/v2rayN/v2rayN $@
|
||||||
|
- EOF
|
||||||
|
- chmod a+x AppRun
|
||||||
363
v2rayN/.gitignore
vendored
363
v2rayN/.gitignore
vendored
@@ -1,363 +0,0 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.rsuser
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
|
||||||
|
|
||||||
# Mono auto generated files
|
|
||||||
mono_crash.*
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Dd]ebugPublic/
|
|
||||||
[Rr]elease/
|
|
||||||
[Rr]eleases/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Ww][Ii][Nn]32/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
[Oo]ut/
|
|
||||||
[Ll]og/
|
|
||||||
[Ll]ogs/
|
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUnit
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
nunit-*.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
|
||||||
ScaffoldingReadMe.txt
|
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.iobj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.svclog
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
|
||||||
coverage*.json
|
|
||||||
coverage*.xml
|
|
||||||
coverage*.info
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
|
||||||
*.nupkg
|
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
|
||||||
*.nuget.targets
|
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
*.appxbundle
|
|
||||||
*.appxupload
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
ClientBin/
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
@@ -2,16 +2,19 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<Copyright>Copyright © 2017-2024 (GPLv3)</Copyright>
|
|
||||||
<FileVersion>1.3.0</FileVersion>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Assets\en-US.json" />
|
<EmbeddedResource Update="Resx\Resource.resx">
|
||||||
<EmbeddedResource Include="Assets\zh-CN.json" />
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
|
||||||
|
<Compile Update="Resx\Resource.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resource.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"Restart_v2rayN": "Start v2rayN, please wait...",
|
|
||||||
"Guidelines": "Please run it from the main application.",
|
|
||||||
"Upgrade_File_Not_Found": "Upgrade failed, file not found.",
|
|
||||||
"In_Progress": "In progress, please wait...",
|
|
||||||
"Try_Terminate_Process": "Try to terminate the v2rayN process.",
|
|
||||||
"Failed_Terminate_Process": "Failed to terminate the v2rayN.Close it manually,or the upgrade may fail.",
|
|
||||||
"Start_Unzipping": "Start extracting the update package.",
|
|
||||||
"Success_Unzipping": "Successfully extracted the update package!",
|
|
||||||
"Failed_Unzipping": "Failed to extract the update package!",
|
|
||||||
"Failed_Upgrade": "Upgrade failed!",
|
|
||||||
"Success_Upgrade": "Upgrade success!",
|
|
||||||
"Information": "Information"
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"Restart_v2rayN": "正在重启,请等待...",
|
|
||||||
"Guidelines": "请从主应用运行!",
|
|
||||||
"Upgrade_File_Not_Found": "升级失败,文件不存在!",
|
|
||||||
"In_Progress": "正在进行中,请等待...",
|
|
||||||
"Try_Terminate_Process": "尝试结束 v2rayN 进程...",
|
|
||||||
"Failed_Terminate_Process": "请手动关闭正在运行的v2rayN,否则可能升级失败。",
|
|
||||||
"Start_Unzipping": "开始解压缩更新包...",
|
|
||||||
"Success_Unzipping": "解压缩更新包成功!",
|
|
||||||
"Failed_Unzipping": "解压缩更新包失败!",
|
|
||||||
"Failed_Upgrade": "升级失败!",
|
|
||||||
"Success_Upgrade": "升级成功!",
|
|
||||||
"Information": "提示"
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
using System.Globalization;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace AmazTool
|
|
||||||
{
|
|
||||||
public class LocalizationHelper
|
|
||||||
{
|
|
||||||
private static Dictionary<string, string> _languageResources = [];
|
|
||||||
|
|
||||||
static LocalizationHelper()
|
|
||||||
{
|
|
||||||
// 加载语言资源
|
|
||||||
LoadLanguageResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void LoadLanguageResources()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var currentLanguage = CultureInfo.CurrentCulture.Name;
|
|
||||||
if (currentLanguage != "zh-CN" && currentLanguage != "en-US")
|
|
||||||
{
|
|
||||||
currentLanguage = "en-US";
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourceName = $"AmazTool.Assets.{currentLanguage}.json";
|
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
|
||||||
|
|
||||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
|
||||||
if (stream == null) return;
|
|
||||||
|
|
||||||
using StreamReader reader = new(stream);
|
|
||||||
var json = reader.ReadToEnd();
|
|
||||||
if (!string.IsNullOrEmpty(json))
|
|
||||||
{
|
|
||||||
_languageResources = JsonSerializer.Deserialize<Dictionary<string, string>>(json) ?? new Dictionary<string, string>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Failed to read language resource file: {ex.Message}");
|
|
||||||
}
|
|
||||||
catch (JsonException ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Failed to parse JSON data: {ex.Message}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine($"Unexpected error occurred: {ex.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetLocalizedValue(string key)
|
|
||||||
{
|
|
||||||
return _languageResources.TryGetValue(key, out var translation) ? translation : key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,26 @@
|
|||||||
namespace AmazTool
|
namespace AmazTool
|
||||||
{
|
{
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 应用程序的主入口点。
|
|
||||||
/// </summary>
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length == 0)
|
if (args.Length == 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Guidelines"));
|
Console.WriteLine(Resx.Resource.Guidelines);
|
||||||
Thread.Sleep(5000);
|
Thread.Sleep(5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileName = Uri.UnescapeDataString(string.Join(" ", args));
|
var argData = Uri.UnescapeDataString(string.Join(" ", args));
|
||||||
UpgradeApp.Upgrade(fileName);
|
if (argData.Equals("rebootas"))
|
||||||
|
{
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
Utils.StartV2RayN();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpgradeApp.Upgrade(argData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
171
v2rayN/AmazTool/Resx/Resource.Designer.cs
generated
Normal file
171
v2rayN/AmazTool/Resx/Resource.Designer.cs
generated
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// 此代码由工具生成。
|
||||||
|
// 运行时版本:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// 对此文件的更改可能会导致不正确的行为,并且如果
|
||||||
|
// 重新生成代码,这些更改将会丢失。
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace AmazTool.Resx {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
||||||
|
/// </summary>
|
||||||
|
// 此类是由 StronglyTypedResourceBuilder
|
||||||
|
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
||||||
|
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
||||||
|
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resource {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resource() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回此类使用的缓存的 ResourceManager 实例。
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AmazTool.Resx.Resource", typeof(Resource).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重写当前线程的 CurrentUICulture 属性,对
|
||||||
|
/// 使用此强类型资源类的所有资源查找执行重写。
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Failed to terminate the v2rayN.Close it manually,or the upgrade may fail. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string FailedTerminateProcess {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("FailedTerminateProcess", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Failed to extract the update package. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string FailedUnzipping {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("FailedUnzipping", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Upgrade failed. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string FailedUpgrade {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("FailedUpgrade", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Please run it from the main application. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string Guidelines {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Guidelines", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Information 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string Information {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Information", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 In progress, please wait... 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string InProgress {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InProgress", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Start v2rayN, please wait... 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string Restartv2rayN {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Restartv2rayN", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Start extracting the update package... 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string StartUnzipping {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("StartUnzipping", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Successfully extracted the update package. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string SuccessUnzipping {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SuccessUnzipping", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Upgrade success. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string SuccessUpgrade {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SuccessUpgrade", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Try to terminate the v2rayN process... 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string TryTerminateProcess {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TryTerminateProcess", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Upgrade failed, file not found. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string UpgradeFileNotFound {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("UpgradeFileNotFound", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
156
v2rayN/AmazTool/Resx/Resource.resx
Normal file
156
v2rayN/AmazTool/Resx/Resource.resx
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="Restartv2rayN" xml:space="preserve">
|
||||||
|
<value>Start v2rayN, please wait...</value>
|
||||||
|
</data>
|
||||||
|
<data name="Guidelines" xml:space="preserve">
|
||||||
|
<value>Please run it from the main application.</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpgradeFileNotFound" xml:space="preserve">
|
||||||
|
<value>Upgrade failed, file not found.</value>
|
||||||
|
</data>
|
||||||
|
<data name="InProgress" xml:space="preserve">
|
||||||
|
<value>In progress, please wait...</value>
|
||||||
|
</data>
|
||||||
|
<data name="TryTerminateProcess" xml:space="preserve">
|
||||||
|
<value>Try to terminate the v2rayN process...</value>
|
||||||
|
</data>
|
||||||
|
<data name="FailedTerminateProcess" xml:space="preserve">
|
||||||
|
<value>Failed to terminate the v2rayN.Close it manually,or the upgrade may fail.</value>
|
||||||
|
</data>
|
||||||
|
<data name="StartUnzipping" xml:space="preserve">
|
||||||
|
<value>Start extracting the update package...</value>
|
||||||
|
</data>
|
||||||
|
<data name="SuccessUnzipping" xml:space="preserve">
|
||||||
|
<value>Successfully extracted the update package.</value>
|
||||||
|
</data>
|
||||||
|
<data name="FailedUnzipping" xml:space="preserve">
|
||||||
|
<value>Failed to extract the update package.</value>
|
||||||
|
</data>
|
||||||
|
<data name="FailedUpgrade" xml:space="preserve">
|
||||||
|
<value>Upgrade failed.</value>
|
||||||
|
</data>
|
||||||
|
<data name="SuccessUpgrade" xml:space="preserve">
|
||||||
|
<value>Upgrade success.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Information" xml:space="preserve">
|
||||||
|
<value>Information</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<root>
|
<root>
|
||||||
<!--
|
<!--
|
||||||
Microsoft ResX Schema
|
Microsoft ResX Schema
|
||||||
@@ -117,8 +117,40 @@
|
|||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
<data name="Restartv2rayN" xml:space="preserve">
|
||||||
<data name="pac" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<value>正在重启,请等待...</value>
|
||||||
<value>Resources\pac.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value>
|
</data>
|
||||||
|
<data name="Guidelines" xml:space="preserve">
|
||||||
|
<value>请从主应用运行。</value>
|
||||||
|
</data>
|
||||||
|
<data name="UpgradeFileNotFound" xml:space="preserve">
|
||||||
|
<value>升级失败,文件不存在。</value>
|
||||||
|
</data>
|
||||||
|
<data name="InProgress" xml:space="preserve">
|
||||||
|
<value>正在进行中,请等待...</value>
|
||||||
|
</data>
|
||||||
|
<data name="TryTerminateProcess" xml:space="preserve">
|
||||||
|
<value>尝试结束 v2rayN 进程...</value>
|
||||||
|
</data>
|
||||||
|
<data name="FailedTerminateProcess" xml:space="preserve">
|
||||||
|
<value>请手动关闭正在运行的v2rayN,否则可能升级失败。</value>
|
||||||
|
</data>
|
||||||
|
<data name="StartUnzipping" xml:space="preserve">
|
||||||
|
<value>开始解压缩更新包...</value>
|
||||||
|
</data>
|
||||||
|
<data name="SuccessUnzipping" xml:space="preserve">
|
||||||
|
<value>解压缩更新包成功。</value>
|
||||||
|
</data>
|
||||||
|
<data name="FailedUnzipping" xml:space="preserve">
|
||||||
|
<value>解压缩更新包失败。</value>
|
||||||
|
</data>
|
||||||
|
<data name="FailedUpgrade" xml:space="preserve">
|
||||||
|
<value>升级失败。</value>
|
||||||
|
</data>
|
||||||
|
<data name="SuccessUpgrade" xml:space="preserve">
|
||||||
|
<value>升级成功。</value>
|
||||||
|
</data>
|
||||||
|
<data name="Information" xml:space="preserve">
|
||||||
|
<value>提示</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -8,24 +8,24 @@ namespace AmazTool
|
|||||||
{
|
{
|
||||||
public static void Upgrade(string fileName)
|
public static void Upgrade(string fileName)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{LocalizationHelper.GetLocalizedValue("Start_Unzipping")}\n{fileName}");
|
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
|
||||||
|
|
||||||
Waiting(9);
|
Utils.Waiting(5);
|
||||||
|
|
||||||
if (!File.Exists(fileName))
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Upgrade_File_Not_Found"));
|
Console.WriteLine(Resx.Resource.UpgradeFileNotFound);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Try_Terminate_Process"));
|
Console.WriteLine(Resx.Resource.TryTerminateProcess);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var existing = Process.GetProcessesByName(V2rayN);
|
var existing = Process.GetProcessesByName(Utils.V2rayN);
|
||||||
foreach (var pp in existing)
|
foreach (var pp in existing)
|
||||||
{
|
{
|
||||||
var path = pp.MainModule?.FileName ?? "";
|
var path = pp.MainModule?.FileName ?? "";
|
||||||
if (path.StartsWith(GetPath(V2rayN)))
|
if (path.StartsWith(Utils.GetPath(Utils.V2rayN)))
|
||||||
{
|
{
|
||||||
pp?.Kill();
|
pp?.Kill();
|
||||||
pp?.WaitForExit(1000);
|
pp?.WaitForExit(1000);
|
||||||
@@ -35,19 +35,19 @@ namespace AmazTool
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// Access may be denied without admin right. The user may not be an administrator.
|
// Access may be denied without admin right. The user may not be an administrator.
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Terminate_Process") + ex.StackTrace);
|
Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Start_Unzipping"));
|
Console.WriteLine(Resx.Resource.StartUnzipping);
|
||||||
StringBuilder sb = new();
|
StringBuilder sb = new();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string thisAppOldFile = $"{GetExePath()}.tmp";
|
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
|
||||||
File.Delete(thisAppOldFile);
|
File.Delete(thisAppOldFile);
|
||||||
string splitKey = "/";
|
var splitKey = "/";
|
||||||
|
|
||||||
using ZipArchive archive = ZipFile.OpenRead(fileName);
|
using var archive = ZipFile.OpenRead(fileName);
|
||||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
foreach (var entry in archive.Entries)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -59,17 +59,35 @@ namespace AmazTool
|
|||||||
Console.WriteLine(entry.FullName);
|
Console.WriteLine(entry.FullName);
|
||||||
|
|
||||||
var lst = entry.FullName.Split(splitKey);
|
var lst = entry.FullName.Split(splitKey);
|
||||||
if (lst.Length == 1) continue;
|
if (lst.Length == 1)
|
||||||
string fullName = string.Join(splitKey, lst[1..lst.Length]);
|
|
||||||
|
|
||||||
if (string.Equals(GetExePath(), GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
File.Move(GetExePath(), thisAppOldFile);
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
string entryOutputPath = GetPath(fullName);
|
var fullName = string.Join(splitKey, lst[1..lst.Length]);
|
||||||
|
|
||||||
|
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
File.Move(Utils.GetExePath(), thisAppOldFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
var entryOutputPath = Utils.GetPath(fullName);
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
|
||||||
|
//In the bin folder, if the file already exists, it will be skipped
|
||||||
|
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
entry.ExtractToFile(entryOutputPath, true);
|
entry.ExtractToFile(entryOutputPath, true);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
entry.ExtractToFile(entryOutputPath, true);
|
||||||
|
}
|
||||||
|
|
||||||
Console.WriteLine(entryOutputPath);
|
Console.WriteLine(entryOutputPath);
|
||||||
}
|
}
|
||||||
@@ -81,58 +99,19 @@ namespace AmazTool
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + ex.StackTrace);
|
Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
|
||||||
//return;
|
//return;
|
||||||
}
|
}
|
||||||
if (sb.Length > 0)
|
if (sb.Length > 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Failed_Upgrade") + sb.ToString());
|
Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
|
||||||
//return;
|
//return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine(LocalizationHelper.GetLocalizedValue("Restart_v2rayN"));
|
Console.WriteLine(Resx.Resource.Restartv2rayN);
|
||||||
Waiting(9);
|
Utils.Waiting(2);
|
||||||
Process process = new()
|
|
||||||
{
|
|
||||||
StartInfo = new()
|
|
||||||
{
|
|
||||||
UseShellExecute = true,
|
|
||||||
FileName = V2rayN,
|
|
||||||
WorkingDirectory = StartupPath()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
process.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetExePath()
|
Utils.StartV2RayN();
|
||||||
{
|
|
||||||
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string StartupPath()
|
|
||||||
{
|
|
||||||
return AppDomain.CurrentDomain.BaseDirectory;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetPath(string fileName)
|
|
||||||
{
|
|
||||||
string startupPath = StartupPath();
|
|
||||||
if (string.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
return startupPath;
|
|
||||||
}
|
|
||||||
return Path.Combine(startupPath, fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Waiting(int second)
|
|
||||||
{
|
|
||||||
for (var i = second; i > 0; i--)
|
|
||||||
{
|
|
||||||
Console.WriteLine(i);
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string V2rayN => "v2rayN";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
52
v2rayN/AmazTool/Utils.cs
Normal file
52
v2rayN/AmazTool/Utils.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace AmazTool
|
||||||
|
{
|
||||||
|
internal class Utils
|
||||||
|
{
|
||||||
|
public static string GetExePath()
|
||||||
|
{
|
||||||
|
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string StartupPath()
|
||||||
|
{
|
||||||
|
return AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetPath(string fileName)
|
||||||
|
{
|
||||||
|
var startupPath = StartupPath();
|
||||||
|
if (string.IsNullOrEmpty(fileName))
|
||||||
|
{
|
||||||
|
return startupPath;
|
||||||
|
}
|
||||||
|
return Path.Combine(startupPath, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string V2rayN => "v2rayN";
|
||||||
|
|
||||||
|
public static void StartV2RayN()
|
||||||
|
{
|
||||||
|
Process process = new()
|
||||||
|
{
|
||||||
|
StartInfo = new()
|
||||||
|
{
|
||||||
|
UseShellExecute = true,
|
||||||
|
FileName = V2rayN,
|
||||||
|
WorkingDirectory = StartupPath()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
process.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Waiting(int second)
|
||||||
|
{
|
||||||
|
for (var i = second; i > 0; i--)
|
||||||
|
{
|
||||||
|
Console.WriteLine(i);
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
v2rayN/Directory.Build.props
Normal file
33
v2rayN/Directory.Build.props
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<Project>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Version>7.10.4</Version>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
|
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||||
|
<NoWarn>CA1031;CS1591;NU1507;CA1416</NoWarn>
|
||||||
|
<Nullable>annotations</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Authors>2dust</Authors>
|
||||||
|
<PackageLicenseExpression>GPL-3.0</PackageLicenseExpression>
|
||||||
|
<Copyright>Copyright © 2017-$([System.DateTime]::UtcNow.Year) $(Authors)</Copyright>
|
||||||
|
<InvariantGlobalization>false</InvariantGlobalization>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||||
|
<DebugType>embedded</DebugType>
|
||||||
|
<EventSourceSupport>false</EventSourceSupport>
|
||||||
|
<StackTraceSupport>false</StackTraceSupport>
|
||||||
|
<MetricsSupport>false</MetricsSupport>
|
||||||
|
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
|
||||||
|
<EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
|
||||||
|
<EnableUnsafeUTF7Encoding>false</EnableUnsafeUTF7Encoding>
|
||||||
|
|
||||||
|
<UseSystemResourceKeys>true</UseSystemResourceKeys>
|
||||||
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
<PublishReadyToRun>false</PublishReadyToRun>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
30
v2rayN/Directory.Packages.props
Normal file
30
v2rayN/Directory.Packages.props
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||||
|
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
|
||||||
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.5" />
|
||||||
|
<PackageVersion Include="Avalonia.Desktop" Version="11.2.5" />
|
||||||
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.5" />
|
||||||
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.5" />
|
||||||
|
<PackageVersion Include="CliWrap" Version="3.8.1" />
|
||||||
|
<PackageVersion Include="Downloader" Version="3.3.3" />
|
||||||
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
|
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
|
||||||
|
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
|
||||||
|
<PackageVersion Include="QRCoder" Version="1.6.0" />
|
||||||
|
<PackageVersion Include="ReactiveUI" Version="20.1.63" />
|
||||||
|
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
|
||||||
|
<PackageVersion Include="ReactiveUI.WPF" Version="20.1.63" />
|
||||||
|
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.5" />
|
||||||
|
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.5" />
|
||||||
|
<PackageVersion Include="Splat.NLog" Version="15.3.1" />
|
||||||
|
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
|
||||||
|
<PackageVersion Include="TaskScheduler" Version="2.12.0" />
|
||||||
|
<PackageVersion Include="WebDav.Client" Version="2.8.0" />
|
||||||
|
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
|
||||||
|
<PackageVersion Include="ZXing.Net.Bindings.SkiaSharp" Version="0.16.14" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
1
v2rayN/GlobalHotKeys
Submodule
1
v2rayN/GlobalHotKeys
Submodule
Submodule v2rayN/GlobalHotKeys added at ef73fa22c4
@@ -1,104 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace PacLib;
|
|
||||||
|
|
||||||
public class PacHandler
|
|
||||||
{
|
|
||||||
private static string _configPath;
|
|
||||||
private static int _httpPort;
|
|
||||||
private static int _pacPort;
|
|
||||||
private static TcpListener? _tcpListener;
|
|
||||||
private static byte[] _writeContent;
|
|
||||||
private static bool _isRunning;
|
|
||||||
private static bool _needRestart = true;
|
|
||||||
|
|
||||||
public static async Task Start(string configPath, int httpPort, int pacPort)
|
|
||||||
{
|
|
||||||
_needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);
|
|
||||||
|
|
||||||
_configPath = configPath;
|
|
||||||
_httpPort = httpPort;
|
|
||||||
_pacPort = pacPort;
|
|
||||||
|
|
||||||
await InitText();
|
|
||||||
|
|
||||||
if (_needRestart)
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
RunListener();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task InitText()
|
|
||||||
{
|
|
||||||
var path = Path.Combine(_configPath, "pac.txt");
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
|
||||||
await File.AppendAllTextAsync(path, Resources.ResourceManager.GetString("pac"));
|
|
||||||
}
|
|
||||||
|
|
||||||
var pacText = (await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
|
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.AppendLine("HTTP/1.0 200 OK");
|
|
||||||
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
|
|
||||||
sb.AppendLine("Connection:close");
|
|
||||||
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
|
|
||||||
sb.AppendLine();
|
|
||||||
sb.Append(pacText);
|
|
||||||
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void RunListener()
|
|
||||||
{
|
|
||||||
_tcpListener = TcpListener.Create(_pacPort);
|
|
||||||
_isRunning = true;
|
|
||||||
_tcpListener.Start();
|
|
||||||
Task.Factory.StartNew(async () =>
|
|
||||||
{
|
|
||||||
while (_isRunning)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!_tcpListener.Pending())
|
|
||||||
{
|
|
||||||
await Task.Delay(10);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var client = await _tcpListener.AcceptTcpClientAsync();
|
|
||||||
await Task.Run(() => { WriteContent(client); });
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, TaskCreationOptions.LongRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void WriteContent(TcpClient client)
|
|
||||||
{
|
|
||||||
var stream = client.GetStream();
|
|
||||||
stream.Write(_writeContent, 0, _writeContent.Length);
|
|
||||||
stream.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Stop()
|
|
||||||
{
|
|
||||||
if (_tcpListener == null) return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_isRunning = false;
|
|
||||||
_tcpListener.Stop();
|
|
||||||
_tcpListener = null;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Update="Resources.Designer.cs">
|
|
||||||
<DesignTime>True</DesignTime>
|
|
||||||
<AutoGen>True</AutoGen>
|
|
||||||
<DependentUpon>Resources.resx</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<EmbeddedResource Update="Resources.resx">
|
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
95
v2rayN/PacLib/Resources.Designer.cs
generated
95
v2rayN/PacLib/Resources.Designer.cs
generated
@@ -1,95 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
// <auto-generated>
|
|
||||||
// 此代码由工具生成。
|
|
||||||
// 运行时版本:4.0.30319.42000
|
|
||||||
//
|
|
||||||
// 对此文件的更改可能会导致不正确的行为,并且如果
|
|
||||||
// 重新生成代码,这些更改将会丢失。
|
|
||||||
// </auto-generated>
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace PacLib {
|
|
||||||
using System;
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 一个强类型的资源类,用于查找本地化的字符串等。
|
|
||||||
/// </summary>
|
|
||||||
// 此类是由 StronglyTypedResourceBuilder
|
|
||||||
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
|
|
||||||
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
|
|
||||||
// (以 /str 作为命令选项),或重新生成 VS 项目。
|
|
||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
|
||||||
internal class Resources {
|
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
|
||||||
|
|
||||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
|
||||||
|
|
||||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
|
||||||
internal Resources() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 返回此类使用的缓存的 ResourceManager 实例。
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
|
||||||
get {
|
|
||||||
if (object.ReferenceEquals(resourceMan, null)) {
|
|
||||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PacLib.Resources", typeof(Resources).Assembly);
|
|
||||||
resourceMan = temp;
|
|
||||||
}
|
|
||||||
return resourceMan;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重写当前线程的 CurrentUICulture 属性,对
|
|
||||||
/// 使用此强类型资源类的所有资源查找执行重写。
|
|
||||||
/// </summary>
|
|
||||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
|
||||||
internal static global::System.Globalization.CultureInfo Culture {
|
|
||||||
get {
|
|
||||||
return resourceCulture;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
resourceCulture = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 var proxy = '__PROXY__';
|
|
||||||
///var rules = [
|
|
||||||
/// [
|
|
||||||
/// [],
|
|
||||||
/// []
|
|
||||||
/// ],
|
|
||||||
/// [
|
|
||||||
/// [
|
|
||||||
/// "aftygh.gov.tw",
|
|
||||||
/// "aide.gov.tw",
|
|
||||||
/// "aliyun.com",
|
|
||||||
/// "arte.gov.tw",
|
|
||||||
/// "baidu.com",
|
|
||||||
/// "chinaso.com",
|
|
||||||
/// "chinaz.com",
|
|
||||||
/// "chukuang.gov.tw",
|
|
||||||
/// "cycab.gov.tw",
|
|
||||||
/// "dbnsa.gov.tw",
|
|
||||||
/// "df.gov.tw",
|
|
||||||
/// "eastcoast-nsa.gov.tw",
|
|
||||||
/// "erv-nsa.gov.tw",
|
|
||||||
/// "grb.gov.tw",
|
|
||||||
/// "haosou.com",
|
|
||||||
/// [字符串的其余部分被截断]"; 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
internal static string pac {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("pac", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
101
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
101
v2rayN/ServiceLib/Common/AesUtils.cs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common
|
||||||
|
{
|
||||||
|
public class AesUtils
|
||||||
|
{
|
||||||
|
private const int KeySize = 256; // AES-256
|
||||||
|
private const int IvSize = 16; // AES block size
|
||||||
|
private const int Iterations = 10000;
|
||||||
|
private static readonly byte[] Salt = Encoding.ASCII.GetBytes("saltysalt".PadRight(16, ' ')); // google浏览器默认盐值
|
||||||
|
private static readonly string DefaultPassword = Utils.GetMd5(Utils.GetHomePath() + "AesUtils");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Plain text</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Base64 encoded cipher text with IV</returns>
|
||||||
|
public static string Encrypt(string text, string? password = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var plaintext = Encoding.UTF8.GetBytes(text);
|
||||||
|
var key = GetKey(password);
|
||||||
|
var iv = GenerateIv();
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
ms.Write(iv, 0, iv.Length);
|
||||||
|
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(plaintext, 0, plaintext.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
var cipherTextWithIv = ms.ToArray();
|
||||||
|
return Convert.ToBase64String(cipherTextWithIv);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decrypt
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cipherTextWithIv">Base64 encoded cipher text with IV</param>
|
||||||
|
/// <param name="password">Password for key derivation or direct key in ASCII bytes</param>
|
||||||
|
/// <returns>Plain text</returns>
|
||||||
|
public static string Decrypt(string cipherTextWithIv, string? password = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(cipherTextWithIv))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var cipherTextWithIvBytes = Convert.FromBase64String(cipherTextWithIv);
|
||||||
|
var key = GetKey(password);
|
||||||
|
|
||||||
|
var iv = new byte[IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, 0, iv, 0, IvSize);
|
||||||
|
|
||||||
|
var cipherText = new byte[cipherTextWithIvBytes.Length - IvSize];
|
||||||
|
Buffer.BlockCopy(cipherTextWithIvBytes, IvSize, cipherText, 0, cipherText.Length);
|
||||||
|
|
||||||
|
using var aes = Aes.Create();
|
||||||
|
aes.Key = key;
|
||||||
|
aes.IV = iv;
|
||||||
|
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
|
||||||
|
{
|
||||||
|
cs.Write(cipherText, 0, cipherText.Length);
|
||||||
|
cs.FlushFinalBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
var plainText = ms.ToArray();
|
||||||
|
return Encoding.UTF8.GetString(plainText);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GetKey(string? password)
|
||||||
|
{
|
||||||
|
if (password.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
password = DefaultPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var pbkdf2 = new Rfc2898DeriveBytes(password, Salt, Iterations, HashAlgorithmName.SHA256);
|
||||||
|
return pbkdf2.GetBytes(KeySize / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte[] GenerateIv()
|
||||||
|
{
|
||||||
|
var randomNumber = new byte[IvSize];
|
||||||
|
|
||||||
|
using var rng = RandomNumberGenerator.Create();
|
||||||
|
rng.GetBytes(randomNumber);
|
||||||
|
return randomNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
using Downloader;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Downloader;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
@@ -10,7 +10,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
public async Task<string?> DownloadStringAsync(IWebProxy? webProxy, string url, string? userAgent, int timeout)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url))
|
if (url.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -18,7 +18,7 @@ namespace ServiceLib.Common
|
|||||||
Uri uri = new(url);
|
Uri uri = new(url);
|
||||||
//Authorization Header
|
//Authorization Header
|
||||||
var headers = new WebHeaderCollection();
|
var headers = new WebHeaderCollection();
|
||||||
if (Utils.IsNotEmpty(uri.UserInfo))
|
if (uri.UserInfo.IsNotEmpty())
|
||||||
{
|
{
|
||||||
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
headers.Add(HttpRequestHeader.Authorization, "Basic " + Utils.Base64Encode(uri.UserInfo));
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
public async Task DownloadDataAsync4Speed(IWebProxy webProxy, string url, IProgress<string> progress, int timeout)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url))
|
if (url.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ namespace ServiceLib.Common
|
|||||||
//};
|
//};
|
||||||
downloader.DownloadProgressChanged += (sender, value) =>
|
downloader.DownloadProgressChanged += (sender, value) =>
|
||||||
{
|
{
|
||||||
var ts = (DateTime.Now - totalDatetime);
|
var ts = DateTime.Now - totalDatetime;
|
||||||
if (progress != null && ts.Seconds > totalSecond)
|
if (progress != null && ts.Seconds > totalSecond)
|
||||||
{
|
{
|
||||||
hasValue = true;
|
hasValue = true;
|
||||||
@@ -119,11 +119,11 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
public async Task DownloadFileAsync(IWebProxy? webProxy, string url, string fileName, IProgress<double> progress, int timeout)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url))
|
if (url.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (fileName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(fileName));
|
throw new ArgumentNullException(nameof(fileName));
|
||||||
}
|
}
|
||||||
@@ -146,10 +146,7 @@ namespace ServiceLib.Common
|
|||||||
var progressPercentage = 0;
|
var progressPercentage = 0;
|
||||||
var hasValue = false;
|
var hasValue = false;
|
||||||
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
await using var downloader = new Downloader.DownloadService(downloadOpt);
|
||||||
downloader.DownloadStarted += (sender, value) =>
|
downloader.DownloadStarted += (sender, value) => progress?.Report(0);
|
||||||
{
|
|
||||||
progress?.Report(0);
|
|
||||||
};
|
|
||||||
downloader.DownloadProgressChanged += (sender, value) =>
|
downloader.DownloadProgressChanged += (sender, value) =>
|
||||||
{
|
{
|
||||||
hasValue = true;
|
hasValue = true;
|
||||||
|
|||||||
61
v2rayN/ServiceLib/Common/EmbedUtils.cs
Normal file
61
v2rayN/ServiceLib/Common/EmbedUtils.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public static class EmbedUtils
|
||||||
|
{
|
||||||
|
private static readonly string _tag = "EmbedUtils";
|
||||||
|
private static readonly ConcurrentDictionary<string, string> _dicEmbedCache = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get embedded text resources
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="res"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string GetEmbedText(string res)
|
||||||
|
{
|
||||||
|
if (_dicEmbedCache.TryGetValue(res, out var value))
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
var result = string.Empty;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var assembly = Assembly.GetExecutingAssembly();
|
||||||
|
using var stream = assembly.GetManifestResourceStream(res);
|
||||||
|
ArgumentNullException.ThrowIfNull(stream);
|
||||||
|
using StreamReader reader = new(stream);
|
||||||
|
result = reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dicEmbedCache.TryAdd(res, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get local storage resources
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string? LoadResource(string? res)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (File.Exists(res))
|
||||||
|
{
|
||||||
|
return File.ReadAllText(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Formats.Tar;
|
using System.Formats.Tar;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
public static class FileManager
|
public static class FileManager
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "FileManager";
|
||||||
|
|
||||||
public static bool ByteArrayToFile(string fileName, byte[] content)
|
public static bool ByteArrayToFile(string fileName, byte[] content)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -15,7 +17,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -30,7 +32,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,7 +62,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,7 +81,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +99,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Utils.IsNotEmpty(ignoredName) && entry.Name.Contains(ignoredName))
|
if (ignoredName.IsNotEmpty() && entry.Name.Contains(ignoredName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -105,13 +107,13 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -130,7 +132,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,31 +150,33 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, string? ignoredName)
|
public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive, bool overwrite, string? ignoredName = null)
|
||||||
{
|
{
|
||||||
// Get information about the source directory
|
// Get information about the source directory
|
||||||
var dir = new DirectoryInfo(sourceDir);
|
var dir = new DirectoryInfo(sourceDir);
|
||||||
|
|
||||||
// Check if the source directory exists
|
// Check if the source directory exists
|
||||||
if (!dir.Exists)
|
if (!dir.Exists)
|
||||||
|
{
|
||||||
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
|
throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}");
|
||||||
|
}
|
||||||
|
|
||||||
// Cache directories before we start copying
|
// Cache directories before we start copying
|
||||||
var dirs = dir.GetDirectories();
|
var dirs = dir.GetDirectories();
|
||||||
|
|
||||||
// Create the destination directory
|
// Create the destination directory
|
||||||
Directory.CreateDirectory(destinationDir);
|
_ = Directory.CreateDirectory(destinationDir);
|
||||||
|
|
||||||
// Get the files in the source directory and copy to the destination directory
|
// Get the files in the source directory and copy to the destination directory
|
||||||
foreach (var file in dir.GetFiles())
|
foreach (var file in dir.GetFiles())
|
||||||
{
|
{
|
||||||
if (Utils.IsNotEmpty(ignoredName) && file.Name.Contains(ignoredName))
|
if (ignoredName.IsNotEmpty() && file.Name.Contains(ignoredName))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -181,7 +185,11 @@ namespace ServiceLib.Common
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var targetFilePath = Path.Combine(destinationDir, file.Name);
|
var targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||||
file.CopyTo(targetFilePath, true);
|
if (!overwrite && File.Exists(targetFilePath))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ = file.CopyTo(targetFilePath, overwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If recursive and copying subdirectories, recursively call this method
|
// If recursive and copying subdirectories, recursively call this method
|
||||||
@@ -190,9 +198,30 @@ namespace ServiceLib.Common
|
|||||||
foreach (var subDir in dirs)
|
foreach (var subDir in dirs)
|
||||||
{
|
{
|
||||||
var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
var newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
||||||
CopyDirectory(subDir.FullName, newDestinationDir, true, ignoredName);
|
CopyDirectory(subDir.FullName, newDestinationDir, true, overwrite, ignoredName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DeleteExpiredFiles(string sourceDir, DateTime dtLine)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(sourceDir, "*.*");
|
||||||
|
foreach (var filePath in files)
|
||||||
|
{
|
||||||
|
var file = new FileInfo(filePath);
|
||||||
|
if (file.CreationTime >= dtLine)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
file.Delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
private static readonly Lazy<HttpClientHelper> _instance = new(() =>
|
private static readonly Lazy<HttpClientHelper> _instance = new(() =>
|
||||||
{
|
{
|
||||||
HttpClientHandler handler = new() { UseCookies = false };
|
SocketsHttpHandler handler = new() { UseCookies = false };
|
||||||
HttpClientHelper helper = new(new HttpClient(handler));
|
HttpClientHelper helper = new(new HttpClient(handler));
|
||||||
return helper;
|
return helper;
|
||||||
});
|
});
|
||||||
@@ -18,12 +18,17 @@ namespace ServiceLib.Common
|
|||||||
public static HttpClientHelper Instance => _instance.Value;
|
public static HttpClientHelper Instance => _instance.Value;
|
||||||
private readonly HttpClient httpClient;
|
private readonly HttpClient httpClient;
|
||||||
|
|
||||||
private HttpClientHelper(HttpClient httpClient) => this.httpClient = httpClient;
|
private HttpClientHelper(HttpClient httpClient)
|
||||||
|
{
|
||||||
|
this.httpClient = httpClient;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<string?> TryGetAsync(string url)
|
public async Task<string?> TryGetAsync(string url)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url))
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -38,13 +43,19 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public async Task<string?> GetAsync(string url)
|
public async Task<string?> GetAsync(string url)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url)) return null;
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return await httpClient.GetStringAsync(url);
|
return await httpClient.GetStringAsync(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
public async Task<string?> GetAsync(HttpClient client, string url, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url)) return null;
|
if (url.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return await client.GetStringAsync(url, token);
|
return await client.GetStringAsync(url, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,13 +64,13 @@ namespace ServiceLib.Common
|
|||||||
var jsonContent = JsonUtils.Serialize(headers);
|
var jsonContent = JsonUtils.Serialize(headers);
|
||||||
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
var content = new StringContent(jsonContent, Encoding.UTF8, MediaTypeNames.Application.Json);
|
||||||
|
|
||||||
var result = await httpClient.PutAsync(url, content);
|
await httpClient.PutAsync(url, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PatchAsync(string url, Dictionary<string, string> headers)
|
public async Task PatchAsync(string url, Dictionary<string, string> headers)
|
||||||
{
|
{
|
||||||
var myContent = JsonUtils.Serialize(headers);
|
var myContent = JsonUtils.Serialize(headers);
|
||||||
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
|
var buffer = Encoding.UTF8.GetBytes(myContent);
|
||||||
var byteContent = new ByteArrayContent(buffer);
|
var byteContent = new ByteArrayContent(buffer);
|
||||||
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
|
||||||
|
|
||||||
@@ -75,11 +86,17 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
ArgumentNullException.ThrowIfNull(url);
|
ArgumentNullException.ThrowIfNull(url);
|
||||||
ArgumentNullException.ThrowIfNull(fileName);
|
ArgumentNullException.ThrowIfNull(fileName);
|
||||||
if (File.Exists(fileName)) File.Delete(fileName);
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
using var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, token);
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode) throw new Exception(response.StatusCode.ToString());
|
if (!response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
throw new Exception(response.StatusCode.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
var total = response.Content.Headers.ContentLength ?? -1L;
|
var total = response.Content.Headers.ContentLength ?? -1L;
|
||||||
var canReportProgress = total != -1 && progress != null;
|
var canReportProgress = total != -1 && progress != null;
|
||||||
@@ -97,7 +114,10 @@ namespace ServiceLib.Common
|
|||||||
var read = await stream.ReadAsync(buffer, token);
|
var read = await stream.ReadAsync(buffer, token);
|
||||||
totalRead += read;
|
totalRead += read;
|
||||||
|
|
||||||
if (read == 0) break;
|
if (read == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
await file.WriteAsync(buffer.AsMemory(0, read), token);
|
await file.WriteAsync(buffer.AsMemory(0, read), token);
|
||||||
|
|
||||||
if (canReportProgress)
|
if (canReportProgress)
|
||||||
@@ -118,7 +138,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
public async Task DownloadDataAsync4Speed(HttpClient client, string url, IProgress<string> progress, CancellationToken token = default)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url))
|
if (url.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(url));
|
throw new ArgumentNullException(nameof(url));
|
||||||
}
|
}
|
||||||
@@ -168,7 +188,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
totalRead += read;
|
totalRead += read;
|
||||||
|
|
||||||
var ts = (DateTime.Now - totalDatetime);
|
var ts = DateTime.Now - totalDatetime;
|
||||||
if (progress != null && ts.Seconds > totalSecond)
|
if (progress != null && ts.Seconds > totalSecond)
|
||||||
{
|
{
|
||||||
totalSecond = ts.Seconds;
|
totalSecond = ts.Seconds;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
@@ -15,28 +15,30 @@ namespace ServiceLib.Common
|
|||||||
public Job()
|
public Job()
|
||||||
{
|
{
|
||||||
handle = CreateJobObject(IntPtr.Zero, null);
|
handle = CreateJobObject(IntPtr.Zero, null);
|
||||||
IntPtr extendedInfoPtr = IntPtr.Zero;
|
var extendedInfoPtr = IntPtr.Zero;
|
||||||
JOBOBJECT_BASIC_LIMIT_INFORMATION info = new()
|
var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION
|
||||||
{
|
{
|
||||||
LimitFlags = 0x2000
|
LimitFlags = 0x2000
|
||||||
};
|
};
|
||||||
|
|
||||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo = new()
|
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION
|
||||||
{
|
{
|
||||||
BasicLimitInformation = info
|
BasicLimitInformation = info
|
||||||
};
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
|
var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
|
||||||
extendedInfoPtr = Marshal.AllocHGlobal(length);
|
extendedInfoPtr = Marshal.AllocHGlobal(length);
|
||||||
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
|
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
|
||||||
|
|
||||||
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr,
|
if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr,
|
||||||
(uint)length))
|
(uint)length))
|
||||||
|
{
|
||||||
throw new Exception(string.Format("Unable to set information. Error: {0}",
|
throw new Exception(string.Format("Unable to set information. Error: {0}",
|
||||||
Marshal.GetLastWin32Error()));
|
Marshal.GetLastWin32Error()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (extendedInfoPtr != IntPtr.Zero)
|
if (extendedInfoPtr != IntPtr.Zero)
|
||||||
@@ -48,7 +50,7 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public bool AddProcess(IntPtr processHandle)
|
public bool AddProcess(IntPtr processHandle)
|
||||||
{
|
{
|
||||||
bool succ = AssignProcessToJobObject(handle, processHandle);
|
var succ = AssignProcessToJobObject(handle, processHandle);
|
||||||
|
|
||||||
if (!succ)
|
if (!succ)
|
||||||
{
|
{
|
||||||
@@ -75,7 +77,10 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
private void Dispose(bool disposing)
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposed) return;
|
if (disposed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
disposed = true;
|
disposed = true;
|
||||||
|
|
||||||
if (disposing)
|
if (disposing)
|
||||||
@@ -103,7 +108,7 @@ namespace ServiceLib.Common
|
|||||||
private static extern IntPtr CreateJobObject(IntPtr a, string? lpName);
|
private static extern IntPtr CreateJobObject(IntPtr a, string? lpName);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength);
|
private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength);
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
|
private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
|
||||||
@@ -120,34 +125,34 @@ namespace ServiceLib.Common
|
|||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct IO_COUNTERS
|
internal struct IO_COUNTERS
|
||||||
{
|
{
|
||||||
public UInt64 ReadOperationCount;
|
public ulong ReadOperationCount;
|
||||||
public UInt64 WriteOperationCount;
|
public ulong WriteOperationCount;
|
||||||
public UInt64 OtherOperationCount;
|
public ulong OtherOperationCount;
|
||||||
public UInt64 ReadTransferCount;
|
public ulong ReadTransferCount;
|
||||||
public UInt64 WriteTransferCount;
|
public ulong WriteTransferCount;
|
||||||
public UInt64 OtherTransferCount;
|
public ulong OtherTransferCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION
|
internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION
|
||||||
{
|
{
|
||||||
public Int64 PerProcessUserTimeLimit;
|
public long PerProcessUserTimeLimit;
|
||||||
public Int64 PerJobUserTimeLimit;
|
public long PerJobUserTimeLimit;
|
||||||
public UInt32 LimitFlags;
|
public uint LimitFlags;
|
||||||
public UIntPtr MinimumWorkingSetSize;
|
public UIntPtr MinimumWorkingSetSize;
|
||||||
public UIntPtr MaximumWorkingSetSize;
|
public UIntPtr MaximumWorkingSetSize;
|
||||||
public UInt32 ActiveProcessLimit;
|
public uint ActiveProcessLimit;
|
||||||
public UIntPtr Affinity;
|
public UIntPtr Affinity;
|
||||||
public UInt32 PriorityClass;
|
public uint PriorityClass;
|
||||||
public UInt32 SchedulingClass;
|
public uint SchedulingClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct SECURITY_ATTRIBUTES
|
public struct SECURITY_ATTRIBUTES
|
||||||
{
|
{
|
||||||
public UInt32 nLength;
|
public uint nLength;
|
||||||
public IntPtr lpSecurityDescriptor;
|
public IntPtr lpSecurityDescriptor;
|
||||||
public Int32 bInheritHandle;
|
public int bInheritHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
public class JsonUtils
|
public class JsonUtils
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "JsonUtils";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DeepCopy
|
/// DeepCopy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -70,8 +72,9 @@ namespace ServiceLib.Common
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <param name="indented"></param>
|
/// <param name="indented"></param>
|
||||||
|
/// <param name="nullValue"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string Serialize(object? obj, bool indented = true)
|
public static string Serialize(object? obj, bool indented = true, bool nullValue = false)
|
||||||
{
|
{
|
||||||
var result = string.Empty;
|
var result = string.Empty;
|
||||||
try
|
try
|
||||||
@@ -82,14 +85,38 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
var options = new JsonSerializerOptions
|
var options = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
WriteIndented = indented ? true : false,
|
WriteIndented = indented,
|
||||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
||||||
};
|
};
|
||||||
result = JsonSerializer.Serialize(obj, options);
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Serialize Object to Json string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj"></param>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static string Serialize(object? obj, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
var result = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -100,38 +127,5 @@ namespace ServiceLib.Common
|
|||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
|
public static JsonNode? SerializeToNode(object? obj) => JsonSerializer.SerializeToNode(obj);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Save as json file
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="obj"></param>
|
|
||||||
/// <param name="filePath"></param>
|
|
||||||
/// <param name="nullValue"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static int ToFile(object? obj, string? filePath, bool nullValue = true)
|
|
||||||
{
|
|
||||||
if (filePath is null)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var file = File.Create(filePath);
|
|
||||||
|
|
||||||
var options = new JsonSerializerOptions
|
|
||||||
{
|
|
||||||
WriteIndented = true,
|
|
||||||
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull
|
|
||||||
};
|
|
||||||
|
|
||||||
JsonSerializer.Serialize(file, obj, options);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Config;
|
using NLog.Config;
|
||||||
using NLog.Targets;
|
using NLog.Targets;
|
||||||
|
|
||||||
@@ -25,46 +25,22 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ClearLogs()
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var now = DateTime.Now.AddMonths(-1);
|
|
||||||
var dir = Utils.GetLogPath();
|
|
||||||
var files = Directory.GetFiles(dir, "*.txt");
|
|
||||||
foreach (var filePath in files)
|
|
||||||
{
|
|
||||||
var file = new FileInfo(filePath);
|
|
||||||
if (file.CreationTime >= now) continue;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
file.Delete();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SaveLog(string strContent)
|
public static void SaveLog(string strContent)
|
||||||
{
|
{
|
||||||
if (!LogManager.IsLoggingEnabled()) return;
|
if (!LogManager.IsLoggingEnabled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LogManager.GetLogger("Log1").Info(strContent);
|
LogManager.GetLogger("Log1").Info(strContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveLog(string strTitle, Exception ex)
|
public static void SaveLog(string strTitle, Exception ex)
|
||||||
{
|
{
|
||||||
if (!LogManager.IsLoggingEnabled()) return;
|
if (!LogManager.IsLoggingEnabled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var logger = LogManager.GetLogger("Log2");
|
var logger = LogManager.GetLogger("Log2");
|
||||||
logger.Debug($"{strTitle},{ex.Message}");
|
logger.Debug($"{strTitle},{ex.Message}");
|
||||||
|
|||||||
182
v2rayN/ServiceLib/Common/ProcUtils.cs
Normal file
182
v2rayN/ServiceLib/Common/ProcUtils.cs
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace ServiceLib.Common;
|
||||||
|
|
||||||
|
public static class ProcUtils
|
||||||
|
{
|
||||||
|
private static readonly string _tag = "ProcUtils";
|
||||||
|
|
||||||
|
public static void ProcessStart(string? fileName, string arguments = "")
|
||||||
|
{
|
||||||
|
_ = ProcessStart(fileName, arguments, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int? ProcessStart(string? fileName, string arguments, string? dir)
|
||||||
|
{
|
||||||
|
if (fileName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (fileName.Contains(' '))
|
||||||
|
{
|
||||||
|
fileName = fileName.AppendQuotes();
|
||||||
|
}
|
||||||
|
if (arguments.Contains(' '))
|
||||||
|
{
|
||||||
|
arguments = arguments.AppendQuotes();
|
||||||
|
}
|
||||||
|
|
||||||
|
Process proc = new()
|
||||||
|
{
|
||||||
|
StartInfo = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
UseShellExecute = true,
|
||||||
|
FileName = fileName,
|
||||||
|
Arguments = arguments,
|
||||||
|
WorkingDirectory = dir ?? string.Empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
_ = proc.Start();
|
||||||
|
return dir is null ? null : proc.Id;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RebootAsAdmin(bool blAdmin = true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessStartInfo startInfo = new()
|
||||||
|
{
|
||||||
|
UseShellExecute = true,
|
||||||
|
Arguments = Global.RebootAs,
|
||||||
|
WorkingDirectory = Utils.StartupPath(),
|
||||||
|
FileName = Utils.GetExePath().AppendQuotes(),
|
||||||
|
Verb = blAdmin ? "runas" : null,
|
||||||
|
};
|
||||||
|
_ = Process.Start(startInfo);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task ProcessKill(int pid)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ProcessKill(Process.GetProcessById(pid), false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task ProcessKill(Process? proc, bool review)
|
||||||
|
{
|
||||||
|
if (proc is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetProcessKeyInfo(proc, review, out var procId, out var fileName, out var processName);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Utils.IsNonWindows())
|
||||||
|
{
|
||||||
|
proc?.Kill(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
proc?.Kill();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
proc?.Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
proc?.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(300);
|
||||||
|
await ProcessKillByKeyInfo(review, procId, fileName, processName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GetProcessKeyInfo(Process? proc, bool review, out int? procId, out string? fileName, out string? processName)
|
||||||
|
{
|
||||||
|
procId = null;
|
||||||
|
fileName = null;
|
||||||
|
processName = null;
|
||||||
|
if (!review)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
procId = proc?.Id;
|
||||||
|
fileName = proc?.MainModule?.FileName;
|
||||||
|
processName = proc?.ProcessName;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task ProcessKillByKeyInfo(bool review, int? procId, string? fileName, string? processName)
|
||||||
|
{
|
||||||
|
if (review && procId != null && fileName != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var lstProc = Process.GetProcessesByName(processName);
|
||||||
|
foreach (var proc2 in lstProc)
|
||||||
|
{
|
||||||
|
if (proc2.Id == procId)
|
||||||
|
{
|
||||||
|
Logging.SaveLog($"{_tag}, KillProcess not completing the job, procId");
|
||||||
|
await ProcessKill(proc2, false);
|
||||||
|
}
|
||||||
|
if (proc2.MainModule != null && proc2.MainModule?.FileName == fileName)
|
||||||
|
{
|
||||||
|
Logging.SaveLog($"{_tag}, KillProcess not completing the job, fileName");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,7 +60,7 @@ namespace ServiceLib.Common
|
|||||||
var reader = new BarcodeReader();
|
var reader = new BarcodeReader();
|
||||||
var result = reader.Decode(bitmap);
|
var result = reader.Decode(bitmap);
|
||||||
|
|
||||||
if (result != null && Utils.IsNotEmpty(result.Text))
|
if (result != null && result.Text.IsNotEmpty())
|
||||||
{
|
{
|
||||||
return result.Text;
|
return result.Text;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
|
||||||
{
|
|
||||||
public static class QueryableExtension
|
|
||||||
{
|
|
||||||
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> query, string propertyName)
|
|
||||||
{
|
|
||||||
return _OrderBy<T>(query, propertyName, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> query, string propertyName)
|
|
||||||
{
|
|
||||||
return _OrderBy<T>(query, propertyName, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IOrderedQueryable<T> _OrderBy<T>(IQueryable<T> query, string propertyName, bool isDesc)
|
|
||||||
{
|
|
||||||
var methodname = (isDesc) ? "OrderByDescendingInternal" : "OrderByInternal";
|
|
||||||
|
|
||||||
var memberProp = typeof(T).GetProperty(propertyName);
|
|
||||||
|
|
||||||
var method = typeof(QueryableExtension).GetMethod(methodname)
|
|
||||||
.MakeGenericMethod(typeof(T), memberProp.PropertyType);
|
|
||||||
|
|
||||||
return (IOrderedQueryable<T>)method.Invoke(null, new object[] { query, memberProp });
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IOrderedQueryable<T> OrderByInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
|
||||||
{//public
|
|
||||||
return query.OrderBy(_GetLambda<T, TProp>(memberProperty));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IOrderedQueryable<T> OrderByDescendingInternal<T, TProp>(IQueryable<T> query, PropertyInfo memberProperty)
|
|
||||||
{//public
|
|
||||||
return query.OrderByDescending(_GetLambda<T, TProp>(memberProperty));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Expression<Func<T, TProp>> _GetLambda<T, TProp>(PropertyInfo memberProperty)
|
|
||||||
{
|
|
||||||
if (memberProperty.PropertyType != typeof(TProp)) throw new Exception();
|
|
||||||
|
|
||||||
var thisArg = Expression.Parameter(typeof(T));
|
|
||||||
var lambda = Expression.Lambda<Func<T, TProp>>(Expression.Property(thisArg, memberProperty), thisArg);
|
|
||||||
|
|
||||||
return lambda;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
public class SemanticVersion
|
public class SemanticVersion
|
||||||
{
|
{
|
||||||
private int major;
|
private readonly int major;
|
||||||
private int minor;
|
private readonly int minor;
|
||||||
private int patch;
|
private readonly int patch;
|
||||||
private string version;
|
private readonly string version;
|
||||||
|
|
||||||
public SemanticVersion(int major, int minor, int patch)
|
public SemanticVersion(int major, int minor, int patch)
|
||||||
{
|
{
|
||||||
this.major = major;
|
this.major = major;
|
||||||
this.minor = minor;
|
this.minor = minor;
|
||||||
this.patch = patch;
|
this.patch = patch;
|
||||||
this.version = $"{major}.{minor}.{patch}";
|
version = $"{major}.{minor}.{patch}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public SemanticVersion(string? version)
|
public SemanticVersion(string? version)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (version.IsNullOrEmpty())
|
if (string.IsNullOrEmpty(version))
|
||||||
{
|
{
|
||||||
this.major = 0;
|
major = 0;
|
||||||
this.minor = 0;
|
minor = 0;
|
||||||
this.patch = 0;
|
patch = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.version = version.RemovePrefix('v');
|
this.version = version.RemovePrefix('v');
|
||||||
@@ -31,15 +31,15 @@
|
|||||||
var parts = this.version.Split('.');
|
var parts = this.version.Split('.');
|
||||||
if (parts.Length == 2)
|
if (parts.Length == 2)
|
||||||
{
|
{
|
||||||
this.major = int.Parse(parts[0]);
|
major = int.Parse(parts.First());
|
||||||
this.minor = int.Parse(parts[1]);
|
minor = int.Parse(parts.Last());
|
||||||
this.patch = 0;
|
patch = 0;
|
||||||
}
|
}
|
||||||
else if (parts.Length is 3 or 4)
|
else if (parts.Length is 3 or 4)
|
||||||
{
|
{
|
||||||
this.major = int.Parse(parts[0]);
|
major = int.Parse(parts[0]);
|
||||||
this.minor = int.Parse(parts[1]);
|
minor = int.Parse(parts[1]);
|
||||||
this.patch = int.Parse(parts[2]);
|
patch = int.Parse(parts[2]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -48,9 +48,9 @@
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
this.major = 0;
|
major = 0;
|
||||||
this.minor = 0;
|
minor = 0;
|
||||||
this.patch = 0;
|
patch = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
{
|
{
|
||||||
if (obj is SemanticVersion other)
|
if (obj is SemanticVersion other)
|
||||||
{
|
{
|
||||||
return this.major == other.major && this.minor == other.minor && this.patch == other.patch;
|
return major == other.major && minor == other.minor && patch == other.patch;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return this.major.GetHashCode() ^ this.minor.GetHashCode() ^ this.patch.GetHashCode();
|
return major.GetHashCode() ^ minor.GetHashCode() ^ patch.GetHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -77,18 +77,18 @@
|
|||||||
/// <returns>major.minor.patch</returns>
|
/// <returns>major.minor.patch</returns>
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return this.version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ToVersionString(string? prefix = null)
|
public string ToVersionString(string? prefix = null)
|
||||||
{
|
{
|
||||||
if (prefix == null)
|
if (prefix == null)
|
||||||
{
|
{
|
||||||
return this.version;
|
return version;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return $"{prefix}{this.version}";
|
return $"{prefix}{version}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,31 +108,31 @@
|
|||||||
|
|
||||||
private bool GreaterEquals(SemanticVersion other)
|
private bool GreaterEquals(SemanticVersion other)
|
||||||
{
|
{
|
||||||
if (this.major < other.major)
|
if (major < other.major)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (this.major > other.major)
|
else if (major > other.major)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this.minor < other.minor)
|
if (minor < other.minor)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (this.minor > other.minor)
|
else if (minor > other.minor)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this.patch < other.patch)
|
if (patch < other.patch)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (this.patch > other.patch)
|
else if (patch > other.patch)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -146,31 +146,31 @@
|
|||||||
|
|
||||||
private bool LessEquals(SemanticVersion other)
|
private bool LessEquals(SemanticVersion other)
|
||||||
{
|
{
|
||||||
if (this.major < other.major)
|
if (major < other.major)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (this.major > other.major)
|
else if (major > other.major)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this.minor < other.minor)
|
if (minor < other.minor)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (this.minor > other.minor)
|
else if (minor > other.minor)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this.patch < other.patch)
|
if (patch < other.patch)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (this.patch > other.patch)
|
else if (patch > other.patch)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using SQLite;
|
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
@@ -7,7 +7,7 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
private static readonly Lazy<SQLiteHelper> _instance = new(() => new());
|
private static readonly Lazy<SQLiteHelper> _instance = new(() => new());
|
||||||
public static SQLiteHelper Instance => _instance.Value;
|
public static SQLiteHelper Instance => _instance.Value;
|
||||||
private string _connstr;
|
private readonly string _connstr;
|
||||||
private SQLiteConnection _db;
|
private SQLiteConnection _db;
|
||||||
private SQLiteAsyncConnection _dbAsync;
|
private SQLiteAsyncConnection _dbAsync;
|
||||||
private readonly string _configDB = "guiNDB.db";
|
private readonly string _configDB = "guiNDB.db";
|
||||||
@@ -73,5 +73,19 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
return _dbAsync.Table<T>();
|
return _dbAsync.Table<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DisposeDbConnectionAsync()
|
||||||
|
{
|
||||||
|
await Task.Factory.StartNew(() =>
|
||||||
|
{
|
||||||
|
_db?.Close();
|
||||||
|
_db?.Dispose();
|
||||||
|
_db = null;
|
||||||
|
|
||||||
|
_dbAsync?.GetConnection()?.Close();
|
||||||
|
_dbAsync?.GetConnection()?.Dispose();
|
||||||
|
_dbAsync = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
@@ -6,7 +6,7 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
public static bool IsNullOrEmpty([NotNullWhen(false)] this string? value)
|
||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(value);
|
return string.IsNullOrEmpty(value) || string.IsNullOrWhiteSpace(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
|
public static bool IsNullOrWhiteSpace([NotNullWhen(false)] this string? value)
|
||||||
@@ -21,8 +21,11 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
public static bool BeginWithAny(this string s, IEnumerable<char> chars)
|
||||||
{
|
{
|
||||||
if (s.IsNullOrEmpty()) return false;
|
if (s.IsNullOrEmpty())
|
||||||
return chars.Contains(s[0]);
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return chars.Contains(s.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsWhiteSpace(this string value)
|
private static bool IsWhiteSpace(this string value)
|
||||||
@@ -34,7 +37,10 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
while (reader.ReadLine() is { } line)
|
while (reader.ReadLine() is { } line)
|
||||||
{
|
{
|
||||||
if (line.IsWhiteSpace()) continue;
|
if (line.IsWhiteSpace())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
yield return line;
|
yield return line;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,12 +67,17 @@ namespace ServiceLib.Common
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return char.ToUpper(value[0]) + value[1..];
|
return char.ToUpper(value.First()) + value[1..];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string AppendQuotes(this string value)
|
public static string AppendQuotes(this string value)
|
||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(value) ? string.Empty : $"\"{value}\"";
|
return string.IsNullOrEmpty(value) ? string.Empty : $"\"{value}\"";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int ToInt(this string? value, int defaultValue = 0)
|
||||||
|
{
|
||||||
|
return int.TryParse(value, out var result) ? result : defaultValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
using CliWrap;
|
|
||||||
using CliWrap.Buffered;
|
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
@@ -10,143 +8,81 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using CliWrap;
|
||||||
|
using CliWrap.Buffered;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
public class Utils
|
public class Utils
|
||||||
{
|
{
|
||||||
#region 资源操作
|
private static readonly string _tag = "Utils";
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取嵌入文本资源
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="res"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string GetEmbedText(string res)
|
|
||||||
{
|
|
||||||
var result = string.Empty;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var assembly = Assembly.GetExecutingAssembly();
|
|
||||||
using var stream = assembly.GetManifestResourceStream(res);
|
|
||||||
ArgumentNullException.ThrowIfNull(stream);
|
|
||||||
using StreamReader reader = new(stream);
|
|
||||||
result = reader.ReadToEnd();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 取得存储资源
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string? LoadResource(string? res)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(res))
|
|
||||||
{
|
|
||||||
return File.ReadAllText(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion 资源操作
|
|
||||||
|
|
||||||
#region 转换函数
|
#region 转换函数
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 转逗号分隔的字符串
|
/// Convert to comma-separated string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="lst"></param>
|
/// <param name="lst"></param>
|
||||||
/// <param name="wrap"></param>
|
/// <param name="wrap"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string List2String(List<string>? lst, bool wrap = false)
|
public static string List2String(List<string>? lst, bool wrap = false)
|
||||||
{
|
{
|
||||||
try
|
if (lst == null || lst.Count == 0)
|
||||||
{
|
|
||||||
if (lst == null)
|
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
if (wrap)
|
|
||||||
|
var separator = wrap ? "," + Environment.NewLine : ",";
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
return string.Join("," + Environment.NewLine, lst);
|
return string.Join(separator, lst);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return string.Join(",", lst);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 逗号分隔的字符串
|
/// Comma-separated string
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str"></param>
|
/// <param name="str"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static List<string>? String2List(string? str)
|
public static List<string>? String2List(string? str)
|
||||||
{
|
{
|
||||||
try
|
if (string.IsNullOrWhiteSpace(str))
|
||||||
{
|
|
||||||
if (str == null)
|
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = str.Replace(Environment.NewLine, "");
|
try
|
||||||
|
{
|
||||||
|
str = str.Replace(Environment.NewLine, string.Empty);
|
||||||
return new List<string>(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
|
return new List<string>(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 逗号分隔的字符串,先排序后转List
|
/// Comma-separated string, sorted and then converted to List
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str"></param>
|
/// <param name="str"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static List<string>? String2ListSorted(string str)
|
public static List<string>? String2ListSorted(string str)
|
||||||
{
|
{
|
||||||
try
|
var lst = String2List(str);
|
||||||
{
|
lst?.Sort();
|
||||||
str = str.Replace(Environment.NewLine, "");
|
return lst;
|
||||||
List<string> list = new(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
|
|
||||||
list.Sort();
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base64编码
|
/// Base64 Encode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="plainText"></param>
|
/// <param name="plainText"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -159,14 +95,14 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("Base64Encode", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base64解码
|
/// Base64 Decode
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="plainText"></param>
|
/// <param name="plainText"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -174,7 +110,11 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (plainText.IsNullOrEmpty()) return "";
|
if (plainText.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
plainText = plainText.Trim()
|
plainText = plainText.Trim()
|
||||||
.Replace(Environment.NewLine, "")
|
.Replace(Environment.NewLine, "")
|
||||||
.Replace("\n", "")
|
.Replace("\n", "")
|
||||||
@@ -193,24 +133,12 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("Base64Decode", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int ToInt(object? obj)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Convert.ToInt32(obj ?? string.Empty);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool ToBool(object obj)
|
public static bool ToBool(object obj)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -235,55 +163,25 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ToHumanReadable(long amount, out double result, out string unit)
|
|
||||||
{
|
|
||||||
var factor = 1024u;
|
|
||||||
//long KBs = amount / factor;
|
|
||||||
var KBs = amount;
|
|
||||||
if (KBs > 0)
|
|
||||||
{
|
|
||||||
// multi KB
|
|
||||||
var MBs = KBs / factor;
|
|
||||||
if (MBs > 0)
|
|
||||||
{
|
|
||||||
// multi MB
|
|
||||||
var GBs = MBs / factor;
|
|
||||||
if (GBs > 0)
|
|
||||||
{
|
|
||||||
// multi GB
|
|
||||||
var TBs = GBs / factor;
|
|
||||||
if (TBs > 0)
|
|
||||||
{
|
|
||||||
result = TBs + ((GBs % factor) / (factor + 0.0));
|
|
||||||
unit = "TB";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = GBs + ((MBs % factor) / (factor + 0.0));
|
|
||||||
unit = "GB";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = MBs + ((KBs % factor) / (factor + 0.0));
|
|
||||||
unit = "MB";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = KBs + ((amount % factor) / (factor + 0.0));
|
|
||||||
unit = "KB";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result = amount;
|
|
||||||
unit = "B";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string HumanFy(long amount)
|
public static string HumanFy(long amount)
|
||||||
{
|
{
|
||||||
ToHumanReadable(amount, out var result, out var unit);
|
if (amount <= 0)
|
||||||
return $"{result:f1} {unit}";
|
{
|
||||||
|
return $"{amount:f1} B";
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] units = ["KB", "MB", "GB", "TB", "PB"];
|
||||||
|
var unitIndex = 0;
|
||||||
|
double size = amount;
|
||||||
|
|
||||||
|
// Loop and divide by 1024 until a suitable unit is found
|
||||||
|
while (size >= 1024 && unitIndex < units.Length - 1)
|
||||||
|
{
|
||||||
|
size /= 1024;
|
||||||
|
unitIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{size:f1} {units[unitIndex]}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string UrlEncode(string url)
|
public static string UrlEncode(string url)
|
||||||
@@ -299,7 +197,7 @@ namespace ServiceLib.Common
|
|||||||
public static NameValueCollection ParseQueryString(string query)
|
public static NameValueCollection ParseQueryString(string query)
|
||||||
{
|
{
|
||||||
var result = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
|
var result = new NameValueCollection(StringComparer.OrdinalIgnoreCase);
|
||||||
if (IsNullOrEmpty(query))
|
if (query.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -313,8 +211,8 @@ namespace ServiceLib.Common
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = Uri.UnescapeDataString(keyValue[0]);
|
var key = Uri.UnescapeDataString(keyValue.First());
|
||||||
var val = Uri.UnescapeDataString(keyValue[1]);
|
var val = Uri.UnescapeDataString(keyValue.Last());
|
||||||
|
|
||||||
if (result[key] is null)
|
if (result[key] is null)
|
||||||
{
|
{
|
||||||
@@ -345,7 +243,7 @@ namespace ServiceLib.Common
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetPunycode(string url)
|
public static string GetPunycode(string url)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(url))
|
if (url.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
@@ -370,14 +268,15 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public static bool IsBase64String(string? plainText)
|
public static bool IsBase64String(string? plainText)
|
||||||
{
|
{
|
||||||
if (plainText.IsNullOrEmpty()) return false;
|
if (plainText.IsNullOrEmpty())
|
||||||
|
return false;
|
||||||
var buffer = new Span<byte>(new byte[plainText.Length]);
|
var buffer = new Span<byte>(new byte[plainText.Length]);
|
||||||
return Convert.TryFromBase64String(plainText, buffer, out var _);
|
return Convert.TryFromBase64String(plainText, buffer, out var _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Convert2Comma(string text)
|
public static string Convert2Comma(string text)
|
||||||
{
|
{
|
||||||
if (IsNullOrEmpty(text))
|
if (text.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -390,7 +289,7 @@ namespace ServiceLib.Common
|
|||||||
#region 数据检查
|
#region 数据检查
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 判断输入的是否是数字
|
/// Determine if the input is a number
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="oText"></param>
|
/// <param name="oText"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
@@ -399,28 +298,13 @@ namespace ServiceLib.Common
|
|||||||
return oText.All(char.IsNumber);
|
return oText.All(char.IsNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsNullOrEmpty(string? text)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return text == "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsNotEmpty(string? text)
|
|
||||||
{
|
|
||||||
return !string.IsNullOrEmpty(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证Domain地址是否合法
|
/// Validate if the domain address is valid
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="domain"></param>
|
/// <param name="domain"></param>
|
||||||
public static bool IsDomain(string? domain)
|
public static bool IsDomain(string? domain)
|
||||||
{
|
{
|
||||||
if (IsNullOrEmpty(domain))
|
if (domain.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -460,9 +344,12 @@ namespace ServiceLib.Common
|
|||||||
if (IPAddress.TryParse(ip, out var address))
|
if (IPAddress.TryParse(ip, out var address))
|
||||||
{
|
{
|
||||||
var ipBytes = address.GetAddressBytes();
|
var ipBytes = address.GetAddressBytes();
|
||||||
if (ipBytes[0] == 10) return true;
|
if (ipBytes[0] == 10)
|
||||||
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31) return true;
|
return true;
|
||||||
if (ipBytes[0] == 192 && ipBytes[1] == 168) return true;
|
if (ipBytes[0] == 172 && ipBytes[1] >= 16 && ipBytes[1] <= 31)
|
||||||
|
return true;
|
||||||
|
if (ipBytes[0] == 192 && ipBytes[1] == 168)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -476,14 +363,26 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
|
List<IPEndPoint> lstIpEndPoints = new();
|
||||||
var ipEndPoints = ipProperties.GetActiveTcpListeners();
|
List<TcpConnectionInformation> lstTcpConns = new();
|
||||||
//var lstIpEndPoints = new List<IPEndPoint>(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
|
||||||
return ipEndPoints.Any(endPoint => endPoint.Port == port);
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
|
||||||
|
lstIpEndPoints.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
|
||||||
|
lstTcpConns.AddRange(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpConnections());
|
||||||
|
|
||||||
|
if (lstIpEndPoints?.FindIndex(it => it.Port == port) >= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstTcpConns?.FindIndex(it => it.LocalEndPoint.Port == port) >= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -515,33 +414,27 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
#region 杂项
|
#region 杂项
|
||||||
|
|
||||||
public static bool UpgradeAppExists(out string fileName)
|
public static bool UpgradeAppExists(out string upgradeFileName)
|
||||||
{
|
{
|
||||||
fileName = Path.Combine(Utils.StartupPath(), GetExeName("AmazTool"));
|
upgradeFileName = Path.Combine(GetBaseDirectory(), GetExeName("AmazTool"));
|
||||||
return File.Exists(fileName);
|
return File.Exists(upgradeFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 取得版本
|
/// Get version
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetVersion(bool blFull = true)
|
public static string GetVersion(bool blFull = true)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (blFull)
|
return blFull
|
||||||
{
|
? $"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture}"
|
||||||
return
|
: $"{Global.AppName}/{GetVersionInfo()}";
|
||||||
$"{Global.AppName} - V{GetVersionInfo()} - {RuntimeInformation.ProcessArchitecture} - {File.GetLastWriteTime(GetExePath()):yyyy/MM/dd}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return $"{Global.AppName}/{GetVersionInfo()}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Global.AppName;
|
return Global.AppName;
|
||||||
@@ -555,13 +448,18 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return "0.0";
|
return "0.0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetRuntimeInfo()
|
||||||
|
{
|
||||||
|
return $"{Utils.GetVersion()} | {Utils.StartupPath()} | {Utils.GetExePath()} | {Environment.OSVersion}";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 取得GUID
|
/// GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static string GetGuid(bool full = true)
|
public static string GetGuid(bool full = true)
|
||||||
@@ -579,7 +477,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
@@ -590,23 +488,6 @@ namespace ServiceLib.Common
|
|||||||
return Guid.TryParse(strSrc, out _);
|
return Guid.TryParse(strSrc, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ProcessStart(string? fileName, string arguments = "")
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (fileName.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Process.Start(new ProcessStartInfo(fileName, arguments) { UseShellExecute = true });
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Dictionary<string, string> GetSystemHosts()
|
public static Dictionary<string, string> GetSystemHosts()
|
||||||
{
|
{
|
||||||
var systemHosts = new Dictionary<string, string>();
|
var systemHosts = new Dictionary<string, string>();
|
||||||
@@ -620,16 +501,18 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
foreach (var host in hostsList)
|
foreach (var host in hostsList)
|
||||||
{
|
{
|
||||||
if (host.StartsWith("#")) continue;
|
if (host.StartsWith("#"))
|
||||||
|
continue;
|
||||||
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
var hostItem = host.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (hostItem.Length < 2) continue;
|
if (hostItem.Length != 2)
|
||||||
systemHosts.Add(hostItem[1], hostItem[0]);
|
continue;
|
||||||
|
systemHosts.Add(hostItem.Last(), hostItem.First());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return systemHosts;
|
return systemHosts;
|
||||||
@@ -677,10 +560,37 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
#region TempPath
|
#region TempPath
|
||||||
|
|
||||||
|
public static bool HasWritePermission()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//When this file exists, it is equivalent to having no permission to read and write
|
||||||
|
if (File.Exists(Path.Combine(GetBaseDirectory(), "NotStoreConfigHere.txt")))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tempPath = Path.Combine(GetBaseDirectory(), "guiTemps");
|
||||||
|
if (!Directory.Exists(tempPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(tempPath);
|
||||||
|
}
|
||||||
|
var fileName = Path.Combine(tempPath, GetGuid());
|
||||||
|
File.Create(fileName).Close();
|
||||||
|
File.Delete(fileName);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetPath(string fileName)
|
public static string GetPath(string fileName)
|
||||||
{
|
{
|
||||||
var startupPath = StartupPath();
|
var startupPath = StartupPath();
|
||||||
if (IsNullOrEmpty(fileName))
|
if (fileName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return startupPath;
|
return startupPath;
|
||||||
}
|
}
|
||||||
@@ -688,6 +598,11 @@ namespace ServiceLib.Common
|
|||||||
return Path.Combine(startupPath, fileName);
|
return Path.Combine(startupPath, fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetBaseDirectory(string fileName = "")
|
||||||
|
{
|
||||||
|
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetExePath()
|
public static string GetExePath()
|
||||||
{
|
{
|
||||||
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
return Environment.ProcessPath ?? Process.GetCurrentProcess().MainModule?.FileName ?? string.Empty;
|
||||||
@@ -695,7 +610,12 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public static string StartupPath()
|
public static string StartupPath()
|
||||||
{
|
{
|
||||||
return AppDomain.CurrentDomain.BaseDirectory;
|
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
|
||||||
|
{
|
||||||
|
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "v2rayN");
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetBaseDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetTempPath(string filename = "")
|
public static string GetTempPath(string filename = "")
|
||||||
@@ -706,7 +626,7 @@ namespace ServiceLib.Common
|
|||||||
Directory.CreateDirectory(tempPath);
|
Directory.CreateDirectory(tempPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsNullOrEmpty(filename))
|
if (filename.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return tempPath;
|
return tempPath;
|
||||||
}
|
}
|
||||||
@@ -735,7 +655,7 @@ namespace ServiceLib.Common
|
|||||||
Directory.CreateDirectory(tempPath);
|
Directory.CreateDirectory(tempPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(filename))
|
if (filename.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return tempPath;
|
return tempPath;
|
||||||
}
|
}
|
||||||
@@ -762,7 +682,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsNullOrEmpty(filename))
|
if (filename.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return tempPath;
|
return tempPath;
|
||||||
}
|
}
|
||||||
@@ -780,7 +700,7 @@ namespace ServiceLib.Common
|
|||||||
Directory.CreateDirectory(tempPath);
|
Directory.CreateDirectory(tempPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(filename))
|
if (filename.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return tempPath;
|
return tempPath;
|
||||||
}
|
}
|
||||||
@@ -798,7 +718,25 @@ namespace ServiceLib.Common
|
|||||||
Directory.CreateDirectory(tempPath);
|
Directory.CreateDirectory(tempPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(filename))
|
if (filename.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return tempPath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Path.Combine(tempPath, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetBinConfigPath(string filename = "")
|
||||||
|
{
|
||||||
|
var tempPath = Path.Combine(StartupPath(), "binConfigs");
|
||||||
|
if (!Directory.Exists(tempPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(tempPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return tempPath;
|
return tempPath;
|
||||||
}
|
}
|
||||||
@@ -818,6 +756,8 @@ namespace ServiceLib.Common
|
|||||||
|
|
||||||
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
public static bool IsOSX() => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
||||||
|
|
||||||
|
public static bool IsNonWindows() => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
|
||||||
public static string GetExeName(string name)
|
public static string GetExeName(string name)
|
||||||
{
|
{
|
||||||
return IsWindows() ? $"{name}.exe" : name;
|
return IsWindows() ? $"{name}.exe" : name;
|
||||||
@@ -829,38 +769,43 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
|
return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
var id = GetLinuxUserId().Result ?? "1000";
|
|
||||||
if (int.TryParse(id, out var userId))
|
|
||||||
{
|
|
||||||
return userId == 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
//else
|
||||||
}
|
//{
|
||||||
|
// var id = GetLinuxUserId().Result ?? "1000";
|
||||||
|
// if (int.TryParse(id, out var userId))
|
||||||
|
// {
|
||||||
|
// return userId == 0;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task<string?> GetLinuxUserId()
|
private static async Task<string?> GetLinuxUserId()
|
||||||
{
|
{
|
||||||
var arg = new List<string>() { "-c", "id -u" };
|
var arg = new List<string>() { "-c", "id -u" };
|
||||||
return await GetCliWrapOutput("/bin/bash", arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string?> SetLinuxChmod(string? fileName)
|
public static async Task<string?> SetLinuxChmod(string? fileName)
|
||||||
{
|
{
|
||||||
if (fileName.IsNullOrEmpty()) return null;
|
if (fileName.IsNullOrEmpty())
|
||||||
|
return null;
|
||||||
|
if (fileName.Contains(' '))
|
||||||
|
fileName = fileName.AppendQuotes();
|
||||||
|
//File.SetUnixFileMode(fileName, UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute);
|
||||||
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
var arg = new List<string>() { "-c", $"chmod +x {fileName}" };
|
||||||
return await GetCliWrapOutput("/bin/bash", arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string?> GetLinuxFontFamily(string lang)
|
public static async Task<string?> GetLinuxFontFamily(string lang)
|
||||||
{
|
{
|
||||||
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
// var arg = new List<string>() { "-c", $"fc-list :lang={lang} family" };
|
||||||
var arg = new List<string>() { "-c", $"fc-list : family" };
|
var arg = new List<string>() { "-c", $"fc-list : family" };
|
||||||
return await GetCliWrapOutput("/bin/bash", arg);
|
return await GetCliWrapOutput(Global.LinuxBash, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? GetHomePath()
|
public static string? GetHomePath()
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
using Microsoft.Win32;
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace ServiceLib.Common
|
namespace ServiceLib.Common
|
||||||
{
|
{
|
||||||
internal static class WindowsUtils
|
internal static class WindowsUtils
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "WindowsUtils";
|
||||||
|
|
||||||
public static string? RegReadValue(string path, string name, string def)
|
public static string? RegReadValue(string path, string name, string def)
|
||||||
{
|
{
|
||||||
RegistryKey? regKey = null;
|
RegistryKey? regKey = null;
|
||||||
@@ -11,11 +15,11 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
regKey = Registry.CurrentUser.OpenSubKey(path, false);
|
regKey = Registry.CurrentUser.OpenSubKey(path, false);
|
||||||
var value = regKey?.GetValue(name) as string;
|
var value = regKey?.GetValue(name) as string;
|
||||||
return Utils.IsNullOrEmpty(value) ? def : value;
|
return value.IsNullOrEmpty() ? def : value;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -30,7 +34,7 @@ namespace ServiceLib.Common
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
regKey = Registry.CurrentUser.CreateSubKey(path);
|
regKey = Registry.CurrentUser.CreateSubKey(path);
|
||||||
if (Utils.IsNullOrEmpty(value.ToString()))
|
if (value.ToString().IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
regKey?.DeleteValue(name, false);
|
regKey?.DeleteValue(name, false);
|
||||||
}
|
}
|
||||||
@@ -41,12 +45,30 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
regKey?.Close();
|
regKey?.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task RemoveTunDevice()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sum = MD5.HashData(Encoding.UTF8.GetBytes("wintunsingbox_tun"));
|
||||||
|
var guid = new Guid(sum);
|
||||||
|
var pnpUtilPath = @"C:\Windows\System32\pnputil.exe";
|
||||||
|
var arg = $$""" /remove-device "SWD\Wintun\{{{guid}}}" """;
|
||||||
|
|
||||||
|
// Try to remove the device
|
||||||
|
_ = await Utils.GetCliWrapOutput(pnpUtilPath, arg);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using YamlDotNet.Core;
|
using YamlDotNet.Core;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
|
|
||||||
@@ -6,6 +6,8 @@ namespace ServiceLib.Common
|
|||||||
{
|
{
|
||||||
public class YamlUtils
|
public class YamlUtils
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "YamlUtils";
|
||||||
|
|
||||||
#region YAML
|
#region YAML
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -26,7 +28,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("FromYaml", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return deserializer.Deserialize<T>("");
|
return deserializer.Deserialize<T>("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,16 +55,13 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? PreprocessYaml(string str)
|
public static string? PreprocessYaml(string str)
|
||||||
{
|
{
|
||||||
var deserializer = new DeserializerBuilder()
|
|
||||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
|
||||||
.Build();
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var mergingParser = new MergingParser(new Parser(new StringReader(str)));
|
var mergingParser = new MergingParser(new Parser(new StringReader(str)));
|
||||||
@@ -71,7 +70,7 @@ namespace ServiceLib.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("PreprocessYaml", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum ECoreType
|
public enum ECoreType
|
||||||
{
|
{
|
||||||
v2fly = 1,
|
v2fly = 1,
|
||||||
Xray = 2,
|
Xray = 2,
|
||||||
v2fly_v5 = 4,
|
v2fly_v5 = 4,
|
||||||
|
|
||||||
mihomo = 13,
|
mihomo = 13,
|
||||||
|
|
||||||
hysteria = 21,
|
hysteria = 21,
|
||||||
naiveproxy = 22,
|
naiveproxy = 22,
|
||||||
tuic = 23,
|
tuic = 23,
|
||||||
sing_box = 24,
|
sing_box = 24,
|
||||||
juicity = 25,
|
juicity = 25,
|
||||||
hysteria2 = 26,
|
hysteria2 = 26,
|
||||||
|
brook = 27,
|
||||||
|
overtls = 28,
|
||||||
v2rayN = 99
|
v2rayN = 99
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,12 @@
|
|||||||
public enum EInboundProtocol
|
public enum EInboundProtocol
|
||||||
{
|
{
|
||||||
socks = 0,
|
socks = 0,
|
||||||
http,
|
|
||||||
socks2,
|
socks2,
|
||||||
http2,
|
socks3,
|
||||||
pac,
|
pac,
|
||||||
api,
|
api,
|
||||||
api2,
|
api2,
|
||||||
|
mixed,
|
||||||
speedtest = 21
|
speedtest = 21
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Enums
|
namespace ServiceLib.Enums
|
||||||
{
|
{
|
||||||
public enum EMsgCommand
|
public enum EMsgCommand
|
||||||
{
|
{
|
||||||
@@ -6,6 +6,6 @@
|
|||||||
SendMsgView,
|
SendMsgView,
|
||||||
SendSnackMsg,
|
SendSnackMsg,
|
||||||
RefreshProfiles,
|
RefreshProfiles,
|
||||||
StopSpeedtest
|
AppExit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,5 +4,6 @@
|
|||||||
{
|
{
|
||||||
Default = 0,
|
Default = 0,
|
||||||
Russia = 1,
|
Russia = 1,
|
||||||
|
Iran = 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
13
v2rayN/ServiceLib/Enums/ETheme.cs
Normal file
13
v2rayN/ServiceLib/Enums/ETheme.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace ServiceLib.Enums
|
||||||
|
{
|
||||||
|
public enum ETheme
|
||||||
|
{
|
||||||
|
FollowSystem,
|
||||||
|
Dark,
|
||||||
|
Light,
|
||||||
|
Aquatic,
|
||||||
|
Desert,
|
||||||
|
Dusk,
|
||||||
|
NightSky
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
kcp,
|
kcp,
|
||||||
ws,
|
ws,
|
||||||
httpupgrade,
|
httpupgrade,
|
||||||
splithttp,
|
|
||||||
xhttp,
|
xhttp,
|
||||||
h2,
|
h2,
|
||||||
http,
|
http,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib
|
namespace ServiceLib
|
||||||
{
|
{
|
||||||
public class Global
|
public class Global
|
||||||
{
|
{
|
||||||
@@ -7,26 +7,16 @@
|
|||||||
public const string AppName = "v2rayN";
|
public const string AppName = "v2rayN";
|
||||||
public const string GithubUrl = "https://github.com";
|
public const string GithubUrl = "https://github.com";
|
||||||
public const string GithubApiUrl = "https://api.github.com/repos";
|
public const string GithubApiUrl = "https://api.github.com/repos";
|
||||||
public const string V2flyCoreUrl = "https://github.com/v2fly/v2ray-core/releases";
|
|
||||||
public const string XrayCoreUrl = "https://github.com/XTLS/Xray-core/releases";
|
|
||||||
public const string NUrl = @"https://github.com/2dust/v2rayN/releases";
|
|
||||||
public const string MihomoCoreUrl = "https://github.com/MetaCubeX/mihomo/releases";
|
|
||||||
public const string HysteriaCoreUrl = "https://github.com/apernet/hysteria/releases";
|
|
||||||
public const string NaiveproxyCoreUrl = "https://github.com/klzgrad/naiveproxy/releases";
|
|
||||||
public const string TuicCoreUrl = "https://github.com/EAimTY/tuic/releases";
|
|
||||||
public const string SingboxCoreUrl = "https://github.com/SagerNet/sing-box/releases";
|
|
||||||
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
public const string GeoUrl = "https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/{0}.dat";
|
||||||
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
public const string SpeedPingTestUrl = @"https://www.google.com/generate_204";
|
||||||
public const string JuicityCoreUrl = "https://github.com/juicity/juicity/releases";
|
|
||||||
public const string CustomRoutingListUrl = @"https://raw.githubusercontent.com/2dust/v2rayCustomRoutingList/master/";
|
|
||||||
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
public const string SingboxRulesetUrl = @"https://raw.githubusercontent.com/2dust/sing-box-rules/rule-set-{0}/{1}.srs";
|
||||||
public const string IPAPIUrl = "https://ipapi.co/json";
|
public const string IPAPIUrl = "https://api.ip.sb/geoip";
|
||||||
|
|
||||||
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
public const string PromotionUrl = @"aHR0cHM6Ly85LjIzNDQ1Ni54eXovYWJjLmh0bWw=";
|
||||||
public const string ConfigFileName = "guiNConfig.json";
|
public const string ConfigFileName = "guiNConfig.json";
|
||||||
public const string CoreConfigFileName = "config.json";
|
public const string CoreConfigFileName = "config.json";
|
||||||
public const string CorePreConfigFileName = "configPre.json";
|
public const string CorePreConfigFileName = "configPre.json";
|
||||||
public const string CoreSpeedtestConfigFileName = "configSpeedtest.json";
|
public const string CoreSpeedtestConfigFileName = "configTest{0}.json";
|
||||||
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
public const string CoreMultipleLoadConfigFileName = "configMultipleLoad.json";
|
||||||
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
public const string ClashMixinConfigFileName = "Mixin.yaml";
|
||||||
|
|
||||||
@@ -47,6 +37,9 @@
|
|||||||
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
|
public const string ClashMixinYaml = NamespaceSample + "clash_mixin_yaml";
|
||||||
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
public const string ClashTunYaml = NamespaceSample + "clash_tun_yaml";
|
||||||
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
public const string LinuxAutostartConfig = NamespaceSample + "linux_autostart_config";
|
||||||
|
public const string PacFileName = NamespaceSample + "pac";
|
||||||
|
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
|
||||||
|
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
|
||||||
|
|
||||||
public const string DefaultSecurity = "auto";
|
public const string DefaultSecurity = "auto";
|
||||||
public const string DefaultNetwork = "tcp";
|
public const string DefaultNetwork = "tcp";
|
||||||
@@ -62,81 +55,98 @@
|
|||||||
public const string HttpProtocol = "http://";
|
public const string HttpProtocol = "http://";
|
||||||
public const string HttpsProtocol = "https://";
|
public const string HttpsProtocol = "https://";
|
||||||
public const string SocksProtocol = "socks://";
|
public const string SocksProtocol = "socks://";
|
||||||
|
public const string Socks5Protocol = "socks5://";
|
||||||
|
|
||||||
public const string UserEMail = "t@t.tt";
|
public const string UserEMail = "t@t.tt";
|
||||||
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
public const string AutoRunRegPath = @"Software\Microsoft\Windows\CurrentVersion\Run";
|
||||||
public const string AutoRunName = "v2rayNAutoRun";
|
public const string AutoRunName = "v2rayNAutoRun";
|
||||||
public const string CustomIconName = "v2rayN.ico";
|
public const string SystemProxyExceptionsWindows = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
|
||||||
public const string IEProxyExceptions = "localhost;127.*;10.*;172.16.*;172.17.*;172.18.*;172.19.*;172.20.*;172.21.*;172.22.*;172.23.*;172.24.*;172.25.*;172.26.*;172.27.*;172.28.*;172.29.*;172.30.*;172.31.*;192.168.*";
|
public const string SystemProxyExceptionsLinux = "localhost,127.0.0.0/8,::1";
|
||||||
public const string RoutingRuleComma = "<COMMA>";
|
public const string RoutingRuleComma = "<COMMA>";
|
||||||
public const string GrpcGunMode = "gun";
|
public const string GrpcGunMode = "gun";
|
||||||
public const string GrpcMultiMode = "multi";
|
public const string GrpcMultiMode = "multi";
|
||||||
public const int MaxPort = 65536;
|
public const int MaxPort = 65536;
|
||||||
public const string DelayUnit = "";
|
public const int MinFontSize = 8;
|
||||||
public const string SpeedUnit = "";
|
|
||||||
public const int MinFontSize = 10;
|
|
||||||
public const string RebootAs = "rebootas";
|
public const string RebootAs = "rebootas";
|
||||||
|
public const string AvaAssets = "avares://v2rayN/Assets/";
|
||||||
|
public const string LocalAppData = "V2RAYN_LOCAL_APPLICATION_DATA_V2";
|
||||||
|
public const string V2RayLocalAsset = "V2RAY_LOCATION_ASSET";
|
||||||
|
public const string XrayLocalAsset = "XRAY_LOCATION_ASSET";
|
||||||
|
public const int SpeedTestPageSize = 1000;
|
||||||
|
public const string LinuxBash = "/bin/bash";
|
||||||
|
|
||||||
public static readonly List<string> IEProxyProtocols = new() {
|
public static readonly List<string> IEProxyProtocols =
|
||||||
|
[
|
||||||
"{ip}:{http_port}",
|
"{ip}:{http_port}",
|
||||||
"socks={ip}:{socks_port}",
|
"socks={ip}:{socks_port}",
|
||||||
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
||||||
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}",
|
||||||
""
|
""
|
||||||
};
|
];
|
||||||
|
|
||||||
public static readonly List<string> SubConvertUrls = new List<string> {
|
public static readonly List<string> SubConvertUrls =
|
||||||
|
[
|
||||||
@"https://sub.xeton.dev/sub?url={0}",
|
@"https://sub.xeton.dev/sub?url={0}",
|
||||||
@"https://api.dler.io/sub?url={0}",
|
@"https://api.dler.io/sub?url={0}",
|
||||||
@"http://127.0.0.1:25500/sub?url={0}",
|
@"http://127.0.0.1:25500/sub?url={0}",
|
||||||
""
|
""
|
||||||
};
|
];
|
||||||
|
|
||||||
public static readonly List<string> SubConvertConfig = new List<string> {
|
public static readonly List<string> SubConvertConfig =
|
||||||
@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"
|
[@"https://raw.githubusercontent.com/ACL4SSR/ACL4SSR/master/Clash/config/ACL4SSR_Online.ini"];
|
||||||
};
|
|
||||||
|
|
||||||
public static readonly List<string> SubConvertTargets = new List<string> {
|
public static readonly List<string> SubConvertTargets =
|
||||||
|
[
|
||||||
"",
|
"",
|
||||||
"mixed",
|
"mixed",
|
||||||
"v2ray",
|
"v2ray",
|
||||||
"clash",
|
"clash",
|
||||||
"ss",
|
"ss"
|
||||||
};
|
];
|
||||||
|
|
||||||
public static readonly List<string> SpeedTestUrls = new() {
|
public static readonly List<string> SpeedTestUrls =
|
||||||
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
[
|
||||||
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
|
||||||
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
|
||||||
@"https://cachefly.cachefly.net/50mb.test",
|
@"https://cachefly.cachefly.net/50mb.test",
|
||||||
};
|
@"https://speed.cloudflare.com/__down?bytes=10000000",
|
||||||
|
@"https://speed.cloudflare.com/__down?bytes=50000000",
|
||||||
|
@"https://speed.cloudflare.com/__down?bytes=100000000",
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly List<string> SpeedPingTestUrls = new() {
|
public static readonly List<string> SpeedPingTestUrls =
|
||||||
|
[
|
||||||
@"https://www.google.com/generate_204",
|
@"https://www.google.com/generate_204",
|
||||||
@"https://www.gstatic.com/generate_204",
|
@"https://www.gstatic.com/generate_204",
|
||||||
@"https://www.apple.com/library/test/success.html",
|
@"https://www.apple.com/library/test/success.html",
|
||||||
@"http://www.msftconnecttest.com/connecttest.txt",
|
@"http://www.msftconnecttest.com/connecttest.txt"
|
||||||
};
|
];
|
||||||
|
|
||||||
public static readonly List<string> GeoFilesSources = new() {
|
public static readonly List<string> GeoFilesSources =
|
||||||
|
[
|
||||||
"",
|
"",
|
||||||
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
@"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/{0}.dat",
|
||||||
};
|
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-v2ray-rules@release/{0}.dat"
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly List<string> SingboxRulesetSources = new() {
|
public static readonly List<string> SingboxRulesetSources =
|
||||||
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-rules-dat@release/sing-box/rule-set-{0}/{1}.srs",
|
||||||
};
|
@"https://cdn.jsdelivr.net/gh/chocolate4u/Iran-sing-box-rules@rule-set/{1}.srs"
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly List<string> RoutingRulesSources = new() {
|
public static readonly List<string> RoutingRulesSources =
|
||||||
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/template.json",
|
||||||
};
|
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/template.json"
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly List<string> DNSTemplateSources = new() {
|
public static readonly List<string> DNSTemplateSources =
|
||||||
|
[
|
||||||
"",
|
"",
|
||||||
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
|
@"https://cdn.jsdelivr.net/gh/runetfreedom/russia-v2ray-custom-routing-list@main/v2rayN/",
|
||||||
};
|
@"https://cdn.jsdelivr.net/gh/Chocolate4U/Iran-v2ray-rules@main/v2rayN/"
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
public static readonly Dictionary<string, string> UserAgentTexts = new()
|
||||||
{
|
{
|
||||||
@@ -151,66 +161,362 @@
|
|||||||
|
|
||||||
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
|
public static readonly Dictionary<EConfigType, string> ProtocolShares = new()
|
||||||
{
|
{
|
||||||
{EConfigType.VMess,"vmess://"},
|
{ EConfigType.VMess, "vmess://" },
|
||||||
{EConfigType.Shadowsocks,"ss://"},
|
{ EConfigType.Shadowsocks, "ss://" },
|
||||||
{EConfigType.SOCKS,"socks://"},
|
{ EConfigType.SOCKS, "socks://" },
|
||||||
{EConfigType.VLESS,"vless://"},
|
{ EConfigType.VLESS, "vless://" },
|
||||||
{EConfigType.Trojan,"trojan://"},
|
{ EConfigType.Trojan, "trojan://" },
|
||||||
{EConfigType.Hysteria2,"hysteria2://"},
|
{ EConfigType.Hysteria2, "hysteria2://" },
|
||||||
{EConfigType.TUIC,"tuic://"},
|
{ EConfigType.TUIC, "tuic://" },
|
||||||
{EConfigType.WireGuard,"wireguard://"}
|
{ EConfigType.WireGuard, "wireguard://" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
public static readonly Dictionary<EConfigType, string> ProtocolTypes = new()
|
||||||
{
|
{
|
||||||
{EConfigType.VMess,"vmess"},
|
{ EConfigType.VMess, "vmess" },
|
||||||
{EConfigType.Shadowsocks,"shadowsocks"},
|
{ EConfigType.Shadowsocks, "shadowsocks" },
|
||||||
{EConfigType.SOCKS,"socks"},
|
{ EConfigType.SOCKS, "socks" },
|
||||||
{EConfigType.HTTP,"http"},
|
{ EConfigType.HTTP, "http" },
|
||||||
{EConfigType.VLESS,"vless"},
|
{ EConfigType.VLESS, "vless" },
|
||||||
{EConfigType.Trojan,"trojan"},
|
{ EConfigType.Trojan, "trojan" },
|
||||||
{EConfigType.Hysteria2,"hysteria2"},
|
{ EConfigType.Hysteria2, "hysteria2" },
|
||||||
{EConfigType.TUIC,"tuic"},
|
{ EConfigType.TUIC, "tuic" },
|
||||||
{EConfigType.WireGuard,"wireguard"}
|
{ EConfigType.WireGuard, "wireguard" }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static readonly List<string> VmessSecurities = new() { "aes-128-gcm", "chacha20-poly1305", "auto", "none", "zero" };
|
public static readonly List<string> VmessSecurities =
|
||||||
public static readonly List<string> SsSecurities = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "none", "plain" };
|
[
|
||||||
public static readonly List<string> SsSecuritiesInXray = new() { "aes-256-gcm", "aes-128-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" };
|
"aes-128-gcm",
|
||||||
public static readonly List<string> SsSecuritiesInSingbox = new() { "aes-256-gcm", "aes-192-gcm", "aes-128-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "none", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20" };
|
"chacha20-poly1305",
|
||||||
public static readonly List<string> Flows = new() { "", "xtls-rprx-vision", "xtls-rprx-vision-udp443" };
|
"auto",
|
||||||
public static readonly List<string> Networks = new() { "tcp", "kcp", "ws", "httpupgrade", "xhttp", "splithttp", "h2", "quic", "grpc" };
|
"none",
|
||||||
public static readonly List<string> KcpHeaderTypes = new() { "srtp", "utp", "wechat-video", "dtls", "wireguard" };
|
"zero"
|
||||||
public static readonly List<string> CoreTypes = new() { "v2fly", "Xray", "sing_box" };
|
];
|
||||||
public static readonly List<string> CoreTypes4VLESS = new() { "Xray", "sing_box" };
|
|
||||||
public static readonly List<string> DomainStrategies = new() { "AsIs", "IPIfNonMatch", "IPOnDemand" };
|
|
||||||
public static readonly List<string> DomainStrategies4Singbox = new() { "ipv4_only", "ipv6_only", "prefer_ipv4", "prefer_ipv6", "" };
|
|
||||||
public static readonly List<string> DomainMatchers = new() { "linear", "mph", "" };
|
|
||||||
public static readonly List<string> Fingerprints = new() { "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized", "" };
|
|
||||||
public static readonly List<string> UserAgent = new() { "chrome", "firefox", "safari", "edge", "none" };
|
|
||||||
public static readonly List<string> XhttpMode = new() { "auto", "packet-up", "stream-up" };
|
|
||||||
|
|
||||||
public static readonly List<string> AllowInsecure = new() { "true", "false", "" };
|
public static readonly List<string> SsSecurities =
|
||||||
public static readonly List<string> DomainStrategy4Freedoms = new() { "AsIs", "UseIP", "UseIPv4", "UseIPv6", "" };
|
[
|
||||||
public static readonly List<string> SingboxDomainStrategy4Out = new() { "ipv4_only", "prefer_ipv4", "prefer_ipv6", "ipv6_only", "" };
|
"aes-256-gcm",
|
||||||
public static readonly List<string> DomainDNSAddress = ["223.5.5.5", "223.6.6.6", "localhost"];
|
"aes-128-gcm",
|
||||||
public static readonly List<string> SingboxDomainDNSAddress = ["223.5.5.5", "223.6.6.6", "dhcp://auto"];
|
"chacha20-poly1305",
|
||||||
public static readonly List<string> Languages = new() { "zh-Hans", "zh-Hant", "en", "fa-Ir", "ru" };
|
"chacha20-ietf-poly1305",
|
||||||
public static readonly List<string> Alpns = new() { "h3", "h2", "http/1.1", "h3,h2", "h2,http/1.1", "h3,h2,http/1.1", "" };
|
"none",
|
||||||
public static readonly List<string> LogLevels = new() { "debug", "info", "warning", "error", "none" };
|
"plain"
|
||||||
public static readonly List<string> InboundTags = new() { "socks", "http", "socks2", "http2" };
|
];
|
||||||
public static readonly List<string> RuleProtocols = new() { "http", "tls", "bittorrent" };
|
|
||||||
public static readonly List<string> RuleNetworks = new() { "", "tcp", "udp", "tcp,udp" };
|
|
||||||
public static readonly List<string> destOverrideProtocols = ["http", "tls", "quic", "fakedns", "fakedns+others"];
|
|
||||||
public static readonly List<string> TunMtus = new() { "1280", "1408", "1500", "9000" };
|
|
||||||
public static readonly List<string> TunStacks = new() { "gvisor", "system" };
|
|
||||||
public static readonly List<string> PresetMsgFilters = new() { "proxy", "direct", "block", "" };
|
|
||||||
public static readonly List<string> SingboxMuxs = new() { "h2mux", "smux", "yamux", "" };
|
|
||||||
public static readonly List<string> TuicCongestionControls = new() { "cubic", "new_reno", "bbr" };
|
|
||||||
|
|
||||||
public static readonly List<string> allowSelectType = new() { "selector", "urltest", "loadbalance", "fallback" };
|
public static readonly List<string> SsSecuritiesInXray =
|
||||||
public static readonly List<string> notAllowTestType = new() { "selector", "urltest", "direct", "reject", "compatible", "pass", "loadbalance", "fallback" };
|
[
|
||||||
public static readonly List<string> proxyVehicleType = new() { "file", "http" };
|
"aes-256-gcm",
|
||||||
|
"aes-128-gcm",
|
||||||
|
"chacha20-poly1305",
|
||||||
|
"chacha20-ietf-poly1305",
|
||||||
|
"xchacha20-poly1305",
|
||||||
|
"xchacha20-ietf-poly1305",
|
||||||
|
"none",
|
||||||
|
"plain",
|
||||||
|
"2022-blake3-aes-128-gcm",
|
||||||
|
"2022-blake3-aes-256-gcm",
|
||||||
|
"2022-blake3-chacha20-poly1305"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> SsSecuritiesInSingbox =
|
||||||
|
[
|
||||||
|
"aes-256-gcm",
|
||||||
|
"aes-192-gcm",
|
||||||
|
"aes-128-gcm",
|
||||||
|
"chacha20-ietf-poly1305",
|
||||||
|
"xchacha20-ietf-poly1305",
|
||||||
|
"none",
|
||||||
|
"2022-blake3-aes-128-gcm",
|
||||||
|
"2022-blake3-aes-256-gcm",
|
||||||
|
"2022-blake3-chacha20-poly1305",
|
||||||
|
"aes-128-ctr",
|
||||||
|
"aes-192-ctr",
|
||||||
|
"aes-256-ctr",
|
||||||
|
"aes-128-cfb",
|
||||||
|
"aes-192-cfb",
|
||||||
|
"aes-256-cfb",
|
||||||
|
"rc4-md5",
|
||||||
|
"chacha20-ietf",
|
||||||
|
"xchacha20"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> Flows =
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"xtls-rprx-vision",
|
||||||
|
"xtls-rprx-vision-udp443"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> Networks =
|
||||||
|
[
|
||||||
|
"tcp",
|
||||||
|
"kcp",
|
||||||
|
"ws",
|
||||||
|
"httpupgrade",
|
||||||
|
"xhttp",
|
||||||
|
"h2",
|
||||||
|
"quic",
|
||||||
|
"grpc"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> KcpHeaderTypes =
|
||||||
|
[
|
||||||
|
"srtp",
|
||||||
|
"utp",
|
||||||
|
"wechat-video",
|
||||||
|
"dtls",
|
||||||
|
"wireguard",
|
||||||
|
"dns"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> CoreTypes =
|
||||||
|
[
|
||||||
|
"Xray",
|
||||||
|
"sing_box"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> DomainStrategies =
|
||||||
|
[
|
||||||
|
"AsIs",
|
||||||
|
"IPIfNonMatch",
|
||||||
|
"IPOnDemand"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> DomainStrategies4Singbox =
|
||||||
|
[
|
||||||
|
"ipv4_only",
|
||||||
|
"ipv6_only",
|
||||||
|
"prefer_ipv4",
|
||||||
|
"prefer_ipv6",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> DomainMatchers =
|
||||||
|
[
|
||||||
|
"linear",
|
||||||
|
"mph",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> Fingerprints =
|
||||||
|
[
|
||||||
|
"chrome",
|
||||||
|
"firefox",
|
||||||
|
"safari",
|
||||||
|
"ios",
|
||||||
|
"android",
|
||||||
|
"edge",
|
||||||
|
"360",
|
||||||
|
"qq",
|
||||||
|
"random",
|
||||||
|
"randomized",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> UserAgent =
|
||||||
|
[
|
||||||
|
"chrome",
|
||||||
|
"firefox",
|
||||||
|
"safari",
|
||||||
|
"edge",
|
||||||
|
"none"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> XhttpMode =
|
||||||
|
[
|
||||||
|
"auto",
|
||||||
|
"packet-up",
|
||||||
|
"stream-up",
|
||||||
|
"stream-one"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> AllowInsecure =
|
||||||
|
[
|
||||||
|
"true",
|
||||||
|
"false",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> DomainStrategy4Freedoms =
|
||||||
|
[
|
||||||
|
"AsIs",
|
||||||
|
"UseIP",
|
||||||
|
"UseIPv4",
|
||||||
|
"UseIPv6",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> SingboxDomainStrategy4Out =
|
||||||
|
[
|
||||||
|
"ipv4_only",
|
||||||
|
"prefer_ipv4",
|
||||||
|
"prefer_ipv6",
|
||||||
|
"ipv6_only",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> DomainDNSAddress =
|
||||||
|
[
|
||||||
|
"223.5.5.5",
|
||||||
|
"223.6.6.6",
|
||||||
|
"localhost"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> SingboxDomainDNSAddress =
|
||||||
|
[
|
||||||
|
"223.5.5.5",
|
||||||
|
"223.6.6.6",
|
||||||
|
"dhcp://auto"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> Languages =
|
||||||
|
[
|
||||||
|
"zh-Hans",
|
||||||
|
"zh-Hant",
|
||||||
|
"en",
|
||||||
|
"fa-Ir",
|
||||||
|
"ru",
|
||||||
|
"hu"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> Alpns =
|
||||||
|
[
|
||||||
|
"h3",
|
||||||
|
"h2",
|
||||||
|
"http/1.1",
|
||||||
|
"h3,h2",
|
||||||
|
"h2,http/1.1",
|
||||||
|
"h3,h2,http/1.1",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> LogLevels =
|
||||||
|
[
|
||||||
|
"debug",
|
||||||
|
"info",
|
||||||
|
"warning",
|
||||||
|
"error",
|
||||||
|
"none"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> InboundTags =
|
||||||
|
[
|
||||||
|
"socks",
|
||||||
|
"socks2",
|
||||||
|
"socks3"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> RuleProtocols =
|
||||||
|
[
|
||||||
|
"http",
|
||||||
|
"tls",
|
||||||
|
"bittorrent"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> RuleNetworks =
|
||||||
|
[
|
||||||
|
"",
|
||||||
|
"tcp",
|
||||||
|
"udp",
|
||||||
|
"tcp,udp"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> destOverrideProtocols =
|
||||||
|
[
|
||||||
|
"http",
|
||||||
|
"tls",
|
||||||
|
"quic",
|
||||||
|
"fakedns",
|
||||||
|
"fakedns+others"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<int> TunMtus =
|
||||||
|
[
|
||||||
|
1280,
|
||||||
|
1408,
|
||||||
|
1500,
|
||||||
|
9000
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> TunStacks =
|
||||||
|
[
|
||||||
|
"gvisor",
|
||||||
|
"system",
|
||||||
|
"mixed"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> PresetMsgFilters =
|
||||||
|
[
|
||||||
|
"proxy",
|
||||||
|
"direct",
|
||||||
|
"block",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> SingboxMuxs =
|
||||||
|
[
|
||||||
|
"h2mux",
|
||||||
|
"smux",
|
||||||
|
"yamux",
|
||||||
|
""
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> TuicCongestionControls =
|
||||||
|
[
|
||||||
|
"cubic",
|
||||||
|
"new_reno",
|
||||||
|
"bbr"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> allowSelectType =
|
||||||
|
[
|
||||||
|
"selector",
|
||||||
|
"urltest",
|
||||||
|
"loadbalance",
|
||||||
|
"fallback"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> notAllowTestType =
|
||||||
|
[
|
||||||
|
"selector",
|
||||||
|
"urltest",
|
||||||
|
"direct",
|
||||||
|
"reject",
|
||||||
|
"compatible",
|
||||||
|
"pass",
|
||||||
|
"loadbalance",
|
||||||
|
"fallback"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> proxyVehicleType =
|
||||||
|
[
|
||||||
|
"file",
|
||||||
|
"http"
|
||||||
|
];
|
||||||
|
|
||||||
|
public static readonly Dictionary<ECoreType, string> CoreUrls = new()
|
||||||
|
{
|
||||||
|
{ ECoreType.v2fly, "v2fly/v2ray-core" },
|
||||||
|
{ ECoreType.v2fly_v5, "v2fly/v2ray-core" },
|
||||||
|
{ ECoreType.Xray, "XTLS/Xray-core" },
|
||||||
|
{ ECoreType.sing_box, "SagerNet/sing-box" },
|
||||||
|
{ ECoreType.mihomo, "MetaCubeX/mihomo" },
|
||||||
|
{ ECoreType.hysteria, "apernet/hysteria" },
|
||||||
|
{ ECoreType.hysteria2, "apernet/hysteria" },
|
||||||
|
{ ECoreType.naiveproxy, "klzgrad/naiveproxy" },
|
||||||
|
{ ECoreType.tuic, "EAimTY/tuic" },
|
||||||
|
{ ECoreType.juicity, "juicity/juicity" },
|
||||||
|
{ ECoreType.brook, "txthinking/brook" },
|
||||||
|
{ ECoreType.overtls, "ShadowsocksR-Live/overtls" },
|
||||||
|
{ ECoreType.v2rayN, "2dust/v2rayN" },
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly List<string> OtherGeoUrls =
|
||||||
|
[
|
||||||
|
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat",
|
||||||
|
@"https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb",
|
||||||
|
@"https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb"
|
||||||
|
];
|
||||||
|
|
||||||
#endregion const
|
#endregion const
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
public sealed class AppHandler
|
public sealed class AppHandler
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
_statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2));
|
||||||
return _statePort2.Value;
|
return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,11 +46,18 @@
|
|||||||
|
|
||||||
public bool InitApp()
|
public bool InitApp()
|
||||||
{
|
{
|
||||||
_config = ConfigHandler.LoadConfig();
|
if (Utils.HasWritePermission() == false)
|
||||||
if (_config == null)
|
{
|
||||||
|
Environment.SetEnvironmentVariable(Global.LocalAppData, "1", EnvironmentVariableTarget.Process);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.Setup();
|
||||||
|
var config = ConfigHandler.LoadConfig();
|
||||||
|
if (config == null)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_config = config;
|
||||||
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
|
Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage);
|
||||||
|
|
||||||
//Under Win10
|
//Under Win10
|
||||||
@@ -70,15 +77,19 @@
|
|||||||
|
|
||||||
public bool InitComponents()
|
public bool InitComponents()
|
||||||
{
|
{
|
||||||
Logging.Setup();
|
Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
|
||||||
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
|
Logging.LoggingEnabled(_config.GuiItem.EnableLog);
|
||||||
Logging.SaveLog($"v2rayN start up | {Utils.GetVersion()} | {Utils.GetExePath()}");
|
|
||||||
Logging.SaveLog($"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
|
||||||
Logging.ClearLogs();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Reset()
|
||||||
|
{
|
||||||
|
_statePort = null;
|
||||||
|
_statePort2 = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Init
|
#endregion Init
|
||||||
|
|
||||||
#region Config
|
#region Config
|
||||||
@@ -94,8 +105,14 @@
|
|||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
{
|
{
|
||||||
_processJob ??= new();
|
_processJob ??= new();
|
||||||
|
try
|
||||||
|
{
|
||||||
_processJob?.AddProcess(processHandle);
|
_processJob?.AddProcess(processHandle);
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Config
|
#endregion Config
|
||||||
@@ -107,14 +124,14 @@
|
|||||||
return await SQLiteHelper.Instance.TableAsync<SubItem>().OrderBy(t => t.Sort).ToListAsync();
|
return await SQLiteHelper.Instance.TableAsync<SubItem>().OrderBy(t => t.Sort).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SubItem?> GetSubItem(string subid)
|
public async Task<SubItem?> GetSubItem(string? subid)
|
||||||
{
|
{
|
||||||
return await SQLiteHelper.Instance.TableAsync<SubItem>().FirstOrDefaultAsync(t => t.Id == subid);
|
return await SQLiteHelper.Instance.TableAsync<SubItem>().FirstOrDefaultAsync(t => t.Id == subid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<ProfileItem>?> ProfileItems(string subid)
|
public async Task<List<ProfileItem>?> ProfileItems(string subid)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
if (subid.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().ToListAsync();
|
return await SQLiteHelper.Instance.TableAsync<ProfileItem>().ToListAsync();
|
||||||
}
|
}
|
||||||
@@ -136,11 +153,11 @@
|
|||||||
from ProfileItem a
|
from ProfileItem a
|
||||||
left join SubItem b on a.subid = b.id
|
left join SubItem b on a.subid = b.id
|
||||||
where 1=1 ";
|
where 1=1 ";
|
||||||
if (Utils.IsNotEmpty(subid))
|
if (subid.IsNotEmpty())
|
||||||
{
|
{
|
||||||
sql += $" and a.subid = '{subid}'";
|
sql += $" and a.subid = '{subid}'";
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(filter))
|
if (filter.IsNotEmpty())
|
||||||
{
|
{
|
||||||
if (filter.Contains('\''))
|
if (filter.Contains('\''))
|
||||||
{
|
{
|
||||||
@@ -152,48 +169,9 @@
|
|||||||
return await SQLiteHelper.Instance.QueryAsync<ProfileItemModel>(sql);
|
return await SQLiteHelper.Instance.QueryAsync<ProfileItemModel>(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<List<ProfileItemModel>?> ProfileItemsEx(string subid, string filter)
|
|
||||||
{
|
|
||||||
var lstModel = await ProfileItems(_config.SubIndexId, filter);
|
|
||||||
|
|
||||||
await ConfigHandler.SetDefaultServer(_config, lstModel);
|
|
||||||
|
|
||||||
var lstServerStat = (_config.GuiItem.EnableStatistics ? StatisticsHandler.Instance.ServerStat : null) ?? [];
|
|
||||||
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
|
||||||
lstModel = (from t in lstModel
|
|
||||||
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
|
|
||||||
from t22 in t2b.DefaultIfEmpty()
|
|
||||||
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
|
|
||||||
from t33 in t3b.DefaultIfEmpty()
|
|
||||||
select new ProfileItemModel
|
|
||||||
{
|
|
||||||
IndexId = t.IndexId,
|
|
||||||
ConfigType = t.ConfigType,
|
|
||||||
Remarks = t.Remarks,
|
|
||||||
Address = t.Address,
|
|
||||||
Port = t.Port,
|
|
||||||
Security = t.Security,
|
|
||||||
Network = t.Network,
|
|
||||||
StreamSecurity = t.StreamSecurity,
|
|
||||||
Subid = t.Subid,
|
|
||||||
SubRemarks = t.SubRemarks,
|
|
||||||
IsActive = t.IndexId == _config.IndexId,
|
|
||||||
Sort = t33 == null ? 0 : t33.Sort,
|
|
||||||
Delay = t33 == null ? 0 : t33.Delay,
|
|
||||||
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay} {Global.DelayUnit}" : string.Empty,
|
|
||||||
SpeedVal = t33?.Speed != 0 ? $"{t33?.Speed} {Global.SpeedUnit}" : string.Empty,
|
|
||||||
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
|
|
||||||
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
|
|
||||||
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
|
|
||||||
TotalUp = t22 == null ? "" : Utils.HumanFy(t22.TotalUp)
|
|
||||||
}).OrderBy(t => t.Sort).ToList();
|
|
||||||
|
|
||||||
return lstModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ProfileItem?> GetProfileItem(string indexId)
|
public async Task<ProfileItem?> GetProfileItem(string indexId)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(indexId))
|
if (indexId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -202,7 +180,7 @@
|
|||||||
|
|
||||||
public async Task<ProfileItem?> GetProfileItemViaRemarks(string? remarks)
|
public async Task<ProfileItem?> GetProfileItemViaRemarks(string? remarks)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(remarks))
|
if (remarks.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -257,16 +235,8 @@
|
|||||||
return (ECoreType)profileItem.CoreType;
|
return (ECoreType)profileItem.CoreType;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_config.CoreTypeItem == null)
|
var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType);
|
||||||
{
|
return item?.CoreType ?? ECoreType.Xray;
|
||||||
return ECoreType.Xray;
|
|
||||||
}
|
|
||||||
var item = _config.CoreTypeItem.FirstOrDefault(it => it.ConfigType == eConfigType);
|
|
||||||
if (item == null)
|
|
||||||
{
|
|
||||||
return ECoreType.Xray;
|
|
||||||
}
|
|
||||||
return item.CoreType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Core Type
|
#endregion Core Type
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
public static class AutoStartupHandler
|
public static class AutoStartupHandler
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "AutoStartupHandler";
|
||||||
|
|
||||||
public static async Task<bool> UpdateTask(Config config)
|
public static async Task<bool> UpdateTask(Config config)
|
||||||
{
|
{
|
||||||
if (Utils.IsWindows())
|
if (Utils.IsWindows())
|
||||||
@@ -25,6 +27,15 @@ namespace ServiceLib.Handler
|
|||||||
await SetTaskLinux();
|
await SetTaskLinux();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (Utils.IsOSX())
|
||||||
|
{
|
||||||
|
await ClearTaskOSX();
|
||||||
|
|
||||||
|
if (config.GuiItem.AutoRun)
|
||||||
|
{
|
||||||
|
await SetTaskOSX();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -39,6 +50,8 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
AutoStartTaskService(autoRunName, "", "");
|
AutoStartTaskService(autoRunName, "", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SetTaskWindows()
|
private static async Task SetTaskWindows()
|
||||||
@@ -58,8 +71,9 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -71,7 +85,7 @@ namespace ServiceLib.Handler
|
|||||||
/// <exception cref="ArgumentNullException"></exception>
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
public static void AutoStartTaskService(string taskName, string fileName, string description)
|
public static void AutoStartTaskService(string taskName, string fileName, string description)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(taskName))
|
if (taskName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -79,7 +93,7 @@ namespace ServiceLib.Handler
|
|||||||
var logonUser = WindowsIdentity.GetCurrent().Name;
|
var logonUser = WindowsIdentity.GetCurrent().Name;
|
||||||
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
|
using var taskService = new Microsoft.Win32.TaskScheduler.TaskService();
|
||||||
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
|
var tasks = taskService.RootFolder.GetTasks(new Regex(taskName));
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (fileName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
foreach (var t in tasks)
|
foreach (var t in tasks)
|
||||||
{
|
{
|
||||||
@@ -95,7 +109,7 @@ namespace ServiceLib.Handler
|
|||||||
task.Settings.RunOnlyIfIdle = false;
|
task.Settings.RunOnlyIfIdle = false;
|
||||||
task.Settings.IdleSettings.StopOnIdleEnd = false;
|
task.Settings.IdleSettings.StopOnIdleEnd = false;
|
||||||
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
|
||||||
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) });
|
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(30) });
|
||||||
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
|
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
|
||||||
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
|
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));
|
||||||
|
|
||||||
@@ -119,15 +133,16 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task SetTaskLinux()
|
private static async Task SetTaskLinux()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var linuxConfig = Utils.GetEmbedText(Global.LinuxAutostartConfig);
|
var linuxConfig = EmbedUtils.GetEmbedText(Global.LinuxAutostartConfig);
|
||||||
if (linuxConfig.IsNotEmpty())
|
if (linuxConfig.IsNotEmpty())
|
||||||
{
|
{
|
||||||
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
|
linuxConfig = linuxConfig.Replace("$ExecPath$", Utils.GetExePath());
|
||||||
@@ -139,7 +154,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,5 +166,77 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion Linux
|
#endregion Linux
|
||||||
|
|
||||||
|
#region macOS
|
||||||
|
|
||||||
|
private static async Task ClearTaskOSX()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var launchAgentPath = GetLaunchAgentPathMacOS();
|
||||||
|
if (File.Exists(launchAgentPath))
|
||||||
|
{
|
||||||
|
var args = new[] { "-c", $"launchctl unload -w \"{launchAgentPath}\"" };
|
||||||
|
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
|
||||||
|
|
||||||
|
File.Delete(launchAgentPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task SetTaskOSX()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var plistContent = GenerateLaunchAgentPlist();
|
||||||
|
var launchAgentPath = GetLaunchAgentPathMacOS();
|
||||||
|
await File.WriteAllTextAsync(launchAgentPath, plistContent);
|
||||||
|
|
||||||
|
var args = new[] { "-c", $"launchctl load -w \"{launchAgentPath}\"" };
|
||||||
|
await Utils.GetCliWrapOutput(Global.LinuxBash, args);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logging.SaveLog(_tag, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLaunchAgentPathMacOS()
|
||||||
|
{
|
||||||
|
var homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
|
||||||
|
var launchAgentPath = Path.Combine(homePath, "Library", "LaunchAgents", $"{Global.AppName}-LaunchAgent.plist");
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(launchAgentPath));
|
||||||
|
return launchAgentPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GenerateLaunchAgentPlist()
|
||||||
|
{
|
||||||
|
var exePath = Utils.GetExePath();
|
||||||
|
var appName = Path.GetFileNameWithoutExtension(exePath);
|
||||||
|
return $@"<?xml version=""1.0"" encoding=""UTF-8""?>
|
||||||
|
<!DOCTYPE plist PUBLIC ""-//Apple//DTD PLIST 1.0//EN"" ""http://www.apple.com/DTDs/PropertyList-1.0.dtd"">
|
||||||
|
<plist version=""1.0"">
|
||||||
|
<dict>
|
||||||
|
<key>Label</key>
|
||||||
|
<string>{Global.AppName}-LaunchAgent</string>
|
||||||
|
<key>ProgramArguments</key>
|
||||||
|
<array>
|
||||||
|
<string>/bin/sh</string>
|
||||||
|
<string>-c</string>
|
||||||
|
<string>if ! pgrep -x ""{appName}"" > /dev/null; then ""{exePath}""; fi</string>
|
||||||
|
</array>
|
||||||
|
<key>RunAtLoad</key>
|
||||||
|
<true/>
|
||||||
|
<key>KeepAlive</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion macOS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using static ServiceLib.Models.ClashProxies;
|
using static ServiceLib.Models.ClashProxies;
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
@@ -7,6 +7,7 @@ namespace ServiceLib.Handler
|
|||||||
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
|
private static readonly Lazy<ClashApiHandler> instance = new(() => new());
|
||||||
public static ClashApiHandler Instance => instance.Value;
|
public static ClashApiHandler Instance => instance.Value;
|
||||||
|
|
||||||
|
private static readonly string _tag = "ClashApiHandler";
|
||||||
private Dictionary<string, ProxiesItem>? _proxies;
|
private Dictionary<string, ProxiesItem>? _proxies;
|
||||||
public Dictionary<string, object> ProfileContent { get; set; }
|
public Dictionary<string, object> ProfileContent { get; set; }
|
||||||
|
|
||||||
@@ -36,24 +37,24 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
|
public void ClashProxiesDelayTest(bool blAll, List<ClashProxyModel> lstProxy, Action<ClashProxyModel?, string> updateFunc)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (blAll)
|
if (blAll)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 5; i++)
|
for (var i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
if (_proxies != null)
|
if (_proxies != null)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Task.Delay(5000).Wait();
|
await Task.Delay(5000);
|
||||||
}
|
}
|
||||||
if (_proxies == null)
|
if (_proxies == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lstProxy = new List<ClashProxyModel>();
|
lstProxy = new List<ClashProxyModel>();
|
||||||
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies)
|
foreach (var kv in _proxies)
|
||||||
{
|
{
|
||||||
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
|
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
|
||||||
{
|
{
|
||||||
@@ -74,7 +75,7 @@ namespace ServiceLib.Handler
|
|||||||
var urlBase = $"{GetApiUrl()}/proxies";
|
var urlBase = $"{GetApiUrl()}/proxies";
|
||||||
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
|
urlBase += @"/{0}/delay?timeout=10000&url=" + AppHandler.Instance.Config.SpeedTestItem.SpeedPingTestUrl;
|
||||||
|
|
||||||
List<Task> tasks = new List<Task>();
|
var tasks = new List<Task>();
|
||||||
foreach (var it in lstProxy)
|
foreach (var it in lstProxy)
|
||||||
{
|
{
|
||||||
if (Global.notAllowTestType.Contains(it.Type.ToLower()))
|
if (Global.notAllowTestType.Contains(it.Type.ToLower()))
|
||||||
@@ -89,9 +90,8 @@ namespace ServiceLib.Handler
|
|||||||
updateFunc?.Invoke(it, result);
|
updateFunc?.Invoke(it, result);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Task.WaitAll(tasks.ToArray());
|
await Task.WhenAll(tasks);
|
||||||
|
await Task.Delay(1000);
|
||||||
Task.Delay(1000).Wait();
|
|
||||||
updateFunc?.Invoke(null, "");
|
updateFunc?.Invoke(null, "");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("GetClashProxyGroups", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,13 +119,13 @@ namespace ServiceLib.Handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = $"{GetApiUrl()}/proxies/{name}";
|
var url = $"{GetApiUrl()}/proxies/{name}";
|
||||||
Dictionary<string, string> headers = new Dictionary<string, string>();
|
var headers = new Dictionary<string, string>();
|
||||||
headers.Add("name", nameNode);
|
headers.Add("name", nameNode);
|
||||||
await HttpClientHelper.Instance.PutAsync(url, headers);
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,13 +147,13 @@ namespace ServiceLib.Handler
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = $"{GetApiUrl()}/configs?force=true";
|
var url = $"{GetApiUrl()}/configs?force=true";
|
||||||
Dictionary<string, string> headers = new Dictionary<string, string>();
|
var headers = new Dictionary<string, string>();
|
||||||
headers.Add("path", filePath);
|
headers.Add("path", filePath);
|
||||||
await HttpClientHelper.Instance.PutAsync(url, headers);
|
await HttpClientHelper.Instance.PutAsync(url, headers);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -184,7 +184,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace ServiceLib.Handler
|
|||||||
public class ConfigHandler
|
public class ConfigHandler
|
||||||
{
|
{
|
||||||
private static readonly string _configRes = Global.ConfigFileName;
|
private static readonly string _configRes = Global.ConfigFileName;
|
||||||
private static readonly object _objLock = new();
|
private static readonly string _tag = "ConfigHandler";
|
||||||
|
|
||||||
#region ConfigHandler
|
#region ConfigHandler
|
||||||
|
|
||||||
@@ -21,8 +21,8 @@ namespace ServiceLib.Handler
|
|||||||
public static Config? LoadConfig()
|
public static Config? LoadConfig()
|
||||||
{
|
{
|
||||||
Config? config = null;
|
Config? config = null;
|
||||||
var result = Utils.LoadResource(Utils.GetConfigPath(_configRes));
|
var result = EmbedUtils.LoadResource(Utils.GetConfigPath(_configRes));
|
||||||
if (Utils.IsNotEmpty(result))
|
if (result.IsNotEmpty())
|
||||||
{
|
{
|
||||||
config = JsonUtils.Deserialize<Config>(result);
|
config = JsonUtils.Deserialize<Config>(result);
|
||||||
}
|
}
|
||||||
@@ -62,15 +62,14 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
if (config.Inbound.Count > 0)
|
if (config.Inbound.Count > 0)
|
||||||
{
|
{
|
||||||
config.Inbound[0].Protocol = EInboundProtocol.socks.ToString();
|
config.Inbound.First().Protocol = EInboundProtocol.socks.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config.RoutingBasicItem ??= new();
|
config.RoutingBasicItem ??= new();
|
||||||
|
if (config.RoutingBasicItem.DomainStrategy.IsNullOrEmpty())
|
||||||
if (Utils.IsNullOrEmpty(config.RoutingBasicItem.DomainStrategy))
|
|
||||||
{
|
{
|
||||||
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies[0];//"IPIfNonMatch";
|
config.RoutingBasicItem.DomainStrategy = Global.DomainStrategies.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
config.KcpItem ??= new KcpItem
|
config.KcpItem ??= new KcpItem
|
||||||
@@ -95,10 +94,7 @@ namespace ServiceLib.Handler
|
|||||||
EnableTun = false,
|
EnableTun = false,
|
||||||
Mtu = 9000,
|
Mtu = 9000,
|
||||||
};
|
};
|
||||||
config.GuiItem ??= new()
|
config.GuiItem ??= new();
|
||||||
{
|
|
||||||
EnableStatistics = false,
|
|
||||||
};
|
|
||||||
config.MsgUIItem ??= new();
|
config.MsgUIItem ??= new();
|
||||||
|
|
||||||
config.UiItem ??= new UIItem()
|
config.UiItem ??= new UIItem()
|
||||||
@@ -107,37 +103,32 @@ namespace ServiceLib.Handler
|
|||||||
};
|
};
|
||||||
config.UiItem.MainColumnItem ??= new();
|
config.UiItem.MainColumnItem ??= new();
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(config.UiItem.CurrentLanguage))
|
if (config.UiItem.CurrentLanguage.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
if (Thread.CurrentThread.CurrentCulture.Name.Equals("zh-cn", StringComparison.CurrentCultureIgnoreCase))
|
config.UiItem.CurrentLanguage = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.Equals("zh", StringComparison.CurrentCultureIgnoreCase)
|
||||||
{
|
? Global.Languages.First()
|
||||||
config.UiItem.CurrentLanguage = Global.Languages[0];
|
: Global.Languages[2];
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
config.UiItem.CurrentLanguage = Global.Languages[2];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config.ConstItem ??= new ConstItem();
|
config.ConstItem ??= new ConstItem();
|
||||||
if (Utils.IsNullOrEmpty(config.ConstItem.DefIEProxyExceptions))
|
|
||||||
{
|
|
||||||
config.ConstItem.DefIEProxyExceptions = Global.IEProxyExceptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.SpeedTestItem ??= new();
|
config.SpeedTestItem ??= new();
|
||||||
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
||||||
{
|
{
|
||||||
config.SpeedTestItem.SpeedTestTimeout = 10;
|
config.SpeedTestItem.SpeedTestTimeout = 10;
|
||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedTestUrl))
|
if (config.SpeedTestItem.SpeedTestUrl.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls[0];
|
config.SpeedTestItem.SpeedTestUrl = Global.SpeedTestUrls.First();
|
||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(config.SpeedTestItem.SpeedPingTestUrl))
|
if (config.SpeedTestItem.SpeedPingTestUrl.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
|
config.SpeedTestItem.SpeedPingTestUrl = Global.SpeedPingTestUrl;
|
||||||
}
|
}
|
||||||
|
if (config.SpeedTestItem.MixedConcurrencyCount < 1)
|
||||||
|
{
|
||||||
|
config.SpeedTestItem.MixedConcurrencyCount = 5;
|
||||||
|
}
|
||||||
|
|
||||||
config.Mux4RayItem ??= new()
|
config.Mux4RayItem ??= new()
|
||||||
{
|
{
|
||||||
@@ -148,7 +139,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
config.Mux4SboxItem ??= new()
|
config.Mux4SboxItem ??= new()
|
||||||
{
|
{
|
||||||
Protocol = Global.SingboxMuxs[0],
|
Protocol = Global.SingboxMuxs.First(),
|
||||||
MaxConnections = 8
|
MaxConnections = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,6 +152,18 @@ namespace ServiceLib.Handler
|
|||||||
config.SystemProxyItem ??= new();
|
config.SystemProxyItem ??= new();
|
||||||
config.WebDavItem ??= new();
|
config.WebDavItem ??= new();
|
||||||
config.CheckUpdateItem ??= new();
|
config.CheckUpdateItem ??= new();
|
||||||
|
config.Fragment4RayItem ??= new()
|
||||||
|
{
|
||||||
|
Packets = "tlshello",
|
||||||
|
Length = "100-200",
|
||||||
|
Interval = "10-20"
|
||||||
|
};
|
||||||
|
config.GlobalHotkeys ??= new();
|
||||||
|
|
||||||
|
if (config.SystemProxyItem.SystemProxyExceptions.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
config.SystemProxyItem.SystemProxyExceptions = Utils.IsWindows() ? Global.SystemProxyExceptionsWindows : Global.SystemProxyExceptionsLinux;
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@@ -171,32 +174,28 @@ namespace ServiceLib.Handler
|
|||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<int> SaveConfig(Config config)
|
public static async Task<int> SaveConfig(Config config)
|
||||||
{
|
|
||||||
lock (_objLock)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//save temp file
|
//save temp file
|
||||||
var resPath = Utils.GetConfigPath(_configRes);
|
var resPath = Utils.GetConfigPath(_configRes);
|
||||||
var tempPath = $"{resPath}_temp";
|
var tempPath = $"{resPath}_temp";
|
||||||
if (JsonUtils.ToFile(config, tempPath) != 0)
|
|
||||||
|
var content = JsonUtils.Serialize(config, true, true);
|
||||||
|
if (content.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
await File.WriteAllTextAsync(tempPath, content);
|
||||||
|
|
||||||
if (File.Exists(resPath))
|
|
||||||
{
|
|
||||||
File.Delete(resPath);
|
|
||||||
}
|
|
||||||
//rename
|
//rename
|
||||||
File.Move(tempPath, resPath);
|
File.Move(tempPath, resPath, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("ToJsonFile", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -218,6 +217,7 @@ namespace ServiceLib.Handler
|
|||||||
item.Remarks = profileItem.Remarks;
|
item.Remarks = profileItem.Remarks;
|
||||||
item.Address = profileItem.Address;
|
item.Address = profileItem.Address;
|
||||||
item.Port = profileItem.Port;
|
item.Port = profileItem.Port;
|
||||||
|
item.Ports = profileItem.Ports;
|
||||||
|
|
||||||
item.Id = profileItem.Id;
|
item.Id = profileItem.Id;
|
||||||
item.AlterId = profileItem.AlterId;
|
item.AlterId = profileItem.AlterId;
|
||||||
@@ -296,7 +296,7 @@ namespace ServiceLib.Handler
|
|||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="indexes"></param>
|
/// <param name="indexes"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<int> RemoveServer(Config config, List<ProfileItem> indexes)
|
public static async Task<int> RemoveServers(Config config, List<ProfileItem> indexes)
|
||||||
{
|
{
|
||||||
var subid = "TempRemoveSubId";
|
var subid = "TempRemoveSubId";
|
||||||
foreach (var item in indexes)
|
foreach (var item in indexes)
|
||||||
@@ -305,7 +305,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
await SQLiteHelper.Instance.UpdateAllAsync(indexes);
|
await SQLiteHelper.Instance.UpdateAllAsync(indexes);
|
||||||
await RemoveServerViaSubid(config, subid, false);
|
await RemoveServersViaSubid(config, subid, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -354,7 +354,7 @@ namespace ServiceLib.Handler
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<int> SetDefaultServerIndex(Config config, string? indexId)
|
public static async Task<int> SetDefaultServerIndex(Config config, string? indexId)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(indexId))
|
if (indexId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -383,7 +383,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
var item = await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(t => t.Port > 0);
|
var item = await SQLiteHelper.Instance.TableAsync<ProfileItem>().FirstOrDefaultAsync(t => t.Port > 0);
|
||||||
return await SetDefaultServerIndex(config, item.IndexId);
|
return await SetDefaultServerIndex(config, item?.IndexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<ProfileItem?> GetDefaultServer(Config config)
|
public static async Task<ProfileItem?> GetDefaultServer(Config config)
|
||||||
@@ -429,7 +429,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].IndexId) - 1;
|
sort = ProfileExHandler.Instance.GetSort(lstProfile.First().IndexId) - 1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -470,7 +470,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProfileExHandler.Instance.SetSort(lstProfile[index].IndexId, sort);
|
ProfileExHandler.Instance.SetSort(lstProfile[index].IndexId, sort);
|
||||||
return 0;
|
return await Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -500,13 +500,13 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
profileItem.Address = newFileName;
|
profileItem.Address = newFileName;
|
||||||
profileItem.ConfigType = EConfigType.Custom;
|
profileItem.ConfigType = EConfigType.Custom;
|
||||||
if (Utils.IsNullOrEmpty(profileItem.Remarks))
|
if (profileItem.Remarks.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Remarks = $"import custom@{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}";
|
profileItem.Remarks = $"import custom@{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}";
|
||||||
}
|
}
|
||||||
@@ -624,7 +624,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
profileItem.Address = profileItem.Address.TrimEx();
|
profileItem.Address = profileItem.Address.TrimEx();
|
||||||
profileItem.Id = profileItem.Id.TrimEx();
|
profileItem.Id = profileItem.Id.TrimEx();
|
||||||
if (Utils.IsNullOrEmpty(profileItem.StreamSecurity))
|
if (profileItem.StreamSecurity.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.StreamSecurity = Global.StreamSecurity;
|
profileItem.StreamSecurity = Global.StreamSecurity;
|
||||||
}
|
}
|
||||||
@@ -654,7 +654,7 @@ namespace ServiceLib.Handler
|
|||||||
profileItem.Path = profileItem.Path.TrimEx();
|
profileItem.Path = profileItem.Path.TrimEx();
|
||||||
profileItem.Network = string.Empty;
|
profileItem.Network = string.Empty;
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(profileItem.StreamSecurity))
|
if (profileItem.StreamSecurity.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.StreamSecurity = Global.StreamSecurity;
|
profileItem.StreamSecurity = Global.StreamSecurity;
|
||||||
}
|
}
|
||||||
@@ -689,11 +689,11 @@ namespace ServiceLib.Handler
|
|||||||
profileItem.HeaderType = Global.TuicCongestionControls.FirstOrDefault()!;
|
profileItem.HeaderType = Global.TuicCongestionControls.FirstOrDefault()!;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(profileItem.StreamSecurity))
|
if (profileItem.StreamSecurity.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.StreamSecurity = Global.StreamSecurity;
|
profileItem.StreamSecurity = Global.StreamSecurity;
|
||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(profileItem.Alpn))
|
if (profileItem.Alpn.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Alpn = "h3";
|
profileItem.Alpn = "h3";
|
||||||
}
|
}
|
||||||
@@ -726,7 +726,7 @@ namespace ServiceLib.Handler
|
|||||||
profileItem.Network = string.Empty;
|
profileItem.Network = string.Empty;
|
||||||
if (profileItem.ShortId.IsNullOrEmpty())
|
if (profileItem.ShortId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.ShortId = Global.TunMtus.FirstOrDefault();
|
profileItem.ShortId = Global.TunMtus.First().ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (profileItem.Id.IsNullOrEmpty())
|
if (profileItem.Id.IsNullOrEmpty())
|
||||||
@@ -760,74 +760,71 @@ namespace ServiceLib.Handler
|
|||||||
Security = t.Security,
|
Security = t.Security,
|
||||||
Network = t.Network,
|
Network = t.Network,
|
||||||
StreamSecurity = t.StreamSecurity,
|
StreamSecurity = t.StreamSecurity,
|
||||||
Delay = t33 == null ? 0 : t33.Delay,
|
Delay = t33?.Delay ?? 0,
|
||||||
Speed = t33 == null ? 0 : t33.Speed,
|
Speed = t33?.Speed ?? 0,
|
||||||
Sort = t33 == null ? 0 : t33.Sort
|
Sort = t33?.Sort ?? 0
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
Enum.TryParse(colName, true, out EServerColName name);
|
Enum.TryParse(colName, true, out EServerColName name);
|
||||||
var propertyName = string.Empty;
|
|
||||||
switch (name)
|
|
||||||
{
|
|
||||||
case EServerColName.ConfigType:
|
|
||||||
case EServerColName.Remarks:
|
|
||||||
case EServerColName.Address:
|
|
||||||
case EServerColName.Port:
|
|
||||||
case EServerColName.Network:
|
|
||||||
case EServerColName.StreamSecurity:
|
|
||||||
propertyName = name.ToString();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EServerColName.DelayVal:
|
|
||||||
propertyName = "Delay";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EServerColName.SpeedVal:
|
|
||||||
propertyName = "Speed";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case EServerColName.SubRemarks:
|
|
||||||
propertyName = "Subid";
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var items = lstProfile.AsQueryable();
|
|
||||||
|
|
||||||
if (asc)
|
if (asc)
|
||||||
{
|
{
|
||||||
lstProfile = items.OrderBy(propertyName).ToList();
|
lstProfile = name switch
|
||||||
|
{
|
||||||
|
EServerColName.ConfigType => lstProfile.OrderBy(t => t.ConfigType).ToList(),
|
||||||
|
EServerColName.Remarks => lstProfile.OrderBy(t => t.Remarks).ToList(),
|
||||||
|
EServerColName.Address => lstProfile.OrderBy(t => t.Address).ToList(),
|
||||||
|
EServerColName.Port => lstProfile.OrderBy(t => t.Port).ToList(),
|
||||||
|
EServerColName.Network => lstProfile.OrderBy(t => t.Network).ToList(),
|
||||||
|
EServerColName.StreamSecurity => lstProfile.OrderBy(t => t.StreamSecurity).ToList(),
|
||||||
|
EServerColName.DelayVal => lstProfile.OrderBy(t => t.Delay).ToList(),
|
||||||
|
EServerColName.SpeedVal => lstProfile.OrderBy(t => t.Speed).ToList(),
|
||||||
|
EServerColName.SubRemarks => lstProfile.OrderBy(t => t.Subid).ToList(),
|
||||||
|
_ => lstProfile
|
||||||
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
lstProfile = items.OrderByDescending(propertyName).ToList();
|
lstProfile = name switch
|
||||||
|
{
|
||||||
|
EServerColName.ConfigType => lstProfile.OrderByDescending(t => t.ConfigType).ToList(),
|
||||||
|
EServerColName.Remarks => lstProfile.OrderByDescending(t => t.Remarks).ToList(),
|
||||||
|
EServerColName.Address => lstProfile.OrderByDescending(t => t.Address).ToList(),
|
||||||
|
EServerColName.Port => lstProfile.OrderByDescending(t => t.Port).ToList(),
|
||||||
|
EServerColName.Network => lstProfile.OrderByDescending(t => t.Network).ToList(),
|
||||||
|
EServerColName.StreamSecurity => lstProfile.OrderByDescending(t => t.StreamSecurity).ToList(),
|
||||||
|
EServerColName.DelayVal => lstProfile.OrderByDescending(t => t.Delay).ToList(),
|
||||||
|
EServerColName.SpeedVal => lstProfile.OrderByDescending(t => t.Speed).ToList(),
|
||||||
|
EServerColName.SubRemarks => lstProfile.OrderByDescending(t => t.Subid).ToList(),
|
||||||
|
_ => lstProfile
|
||||||
|
};
|
||||||
}
|
}
|
||||||
for (int i = 0; i < lstProfile.Count; i++)
|
|
||||||
|
for (var i = 0; i < lstProfile.Count; i++)
|
||||||
{
|
{
|
||||||
ProfileExHandler.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10);
|
ProfileExHandler.Instance.SetSort(lstProfile[i].IndexId, (i + 1) * 10);
|
||||||
}
|
}
|
||||||
if (name == EServerColName.DelayVal)
|
switch (name)
|
||||||
|
{
|
||||||
|
case EServerColName.DelayVal:
|
||||||
{
|
{
|
||||||
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
||||||
foreach (var item in lstProfile)
|
foreach (var item in lstProfile.Where(item => item.Delay <= 0))
|
||||||
{
|
|
||||||
if (item.Delay <= 0)
|
|
||||||
{
|
{
|
||||||
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
case EServerColName.SpeedVal:
|
||||||
if (name == EServerColName.SpeedVal)
|
|
||||||
{
|
{
|
||||||
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
var maxSort = lstProfile.Max(t => t.Sort) + 10;
|
||||||
foreach (var item in lstProfile)
|
foreach (var item in lstProfile.Where(item => item.Speed <= 0))
|
||||||
{
|
|
||||||
if (item.Speed <= 0)
|
|
||||||
{
|
{
|
||||||
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
ProfileExHandler.Instance.SetSort(item.IndexId, maxSort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,7 +858,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(profileItem.Security) && profileItem.Security != Global.None)
|
if (profileItem.Security.IsNotEmpty() && profileItem.Security != Global.None)
|
||||||
{
|
{
|
||||||
profileItem.Security = Global.None;
|
profileItem.Security = Global.None;
|
||||||
}
|
}
|
||||||
@@ -877,7 +874,8 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
List<ProfileItem> lstKeep = new();
|
List<ProfileItem> lstKeep = new();
|
||||||
List<ProfileItem> lstRemove = new();
|
List<ProfileItem> lstRemove = new();
|
||||||
if (!config.GuiItem.KeepOlderDedupl) lstProfile.Reverse();
|
if (!config.GuiItem.KeepOlderDedupl)
|
||||||
|
lstProfile.Reverse();
|
||||||
|
|
||||||
foreach (ProfileItem item in lstProfile)
|
foreach (ProfileItem item in lstProfile)
|
||||||
{
|
{
|
||||||
@@ -890,7 +888,7 @@ namespace ServiceLib.Handler
|
|||||||
lstRemove.Add(item);
|
lstRemove.Add(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await RemoveServer(config, lstRemove);
|
await RemoveServers(config, lstRemove);
|
||||||
|
|
||||||
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
|
return new Tuple<int, int>(lstProfile.Count, lstKeep.Count);
|
||||||
}
|
}
|
||||||
@@ -899,7 +897,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
profileItem.ConfigVersion = 2;
|
profileItem.ConfigVersion = 2;
|
||||||
|
|
||||||
if (Utils.IsNotEmpty(profileItem.StreamSecurity))
|
if (profileItem.StreamSecurity.IsNotEmpty())
|
||||||
{
|
{
|
||||||
if (profileItem.StreamSecurity != Global.StreamSecurity
|
if (profileItem.StreamSecurity != Global.StreamSecurity
|
||||||
&& profileItem.StreamSecurity != Global.StreamSecurityReality)
|
&& profileItem.StreamSecurity != Global.StreamSecurityReality)
|
||||||
@@ -908,24 +906,24 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(profileItem.AllowInsecure))
|
if (profileItem.AllowInsecure.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.AllowInsecure = config.CoreBasicItem.DefAllowInsecure.ToString().ToLower();
|
profileItem.AllowInsecure = config.CoreBasicItem.DefAllowInsecure.ToString().ToLower();
|
||||||
}
|
}
|
||||||
if (Utils.IsNullOrEmpty(profileItem.Fingerprint) && profileItem.StreamSecurity == Global.StreamSecurityReality)
|
if (profileItem.Fingerprint.IsNullOrEmpty() && profileItem.StreamSecurity == Global.StreamSecurityReality)
|
||||||
{
|
{
|
||||||
profileItem.Fingerprint = config.CoreBasicItem.DefFingerprint;
|
profileItem.Fingerprint = config.CoreBasicItem.DefFingerprint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNotEmpty(profileItem.Network) && !Global.Networks.Contains(profileItem.Network))
|
if (profileItem.Network.IsNotEmpty() && !Global.Networks.Contains(profileItem.Network))
|
||||||
{
|
{
|
||||||
profileItem.Network = Global.DefaultNetwork;
|
profileItem.Network = Global.DefaultNetwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
var maxSort = -1;
|
var maxSort = -1;
|
||||||
if (Utils.IsNullOrEmpty(profileItem.IndexId))
|
if (profileItem.IndexId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.IndexId = Utils.GetGuid(false);
|
profileItem.IndexId = Utils.GetGuid(false);
|
||||||
maxSort = ProfileExHandler.Instance.GetMaxSort();
|
maxSort = ProfileExHandler.Instance.GetMaxSort();
|
||||||
@@ -990,7 +988,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("Remove Item", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1026,6 +1024,53 @@ namespace ServiceLib.Handler
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<ProfileItem?> GetPreSocksItem(Config config, ProfileItem node, ECoreType coreType)
|
||||||
|
{
|
||||||
|
ProfileItem? itemSocks = null;
|
||||||
|
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && config.TunModeItem.EnableTun)
|
||||||
|
{
|
||||||
|
itemSocks = new ProfileItem()
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.sing_box,
|
||||||
|
ConfigType = EConfigType.SOCKS,
|
||||||
|
Address = Global.Loopback,
|
||||||
|
Sni = node.Address, //Tun2SocksAddress
|
||||||
|
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
|
||||||
|
{
|
||||||
|
var preCoreType = config.RunningCoreType = config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
|
itemSocks = new ProfileItem()
|
||||||
|
{
|
||||||
|
CoreType = preCoreType,
|
||||||
|
ConfigType = EConfigType.SOCKS,
|
||||||
|
Address = Global.Loopback,
|
||||||
|
Port = node.PreSocksPort.Value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
await Task.CompletedTask;
|
||||||
|
return itemSocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<int> RemoveInvalidServerResult(Config config, string subid)
|
||||||
|
{
|
||||||
|
var lstModel = await AppHandler.Instance.ProfileItems(subid, "");
|
||||||
|
if (lstModel is { Count: <= 0 })
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
var lstProfileExs = await ProfileExHandler.Instance.GetProfileExs();
|
||||||
|
var lstProfile = (from t in lstModel
|
||||||
|
join t2 in lstProfileExs on t.IndexId equals t2.IndexId
|
||||||
|
where t2.Delay == -1
|
||||||
|
select t).ToList();
|
||||||
|
|
||||||
|
await RemoveServers(config, JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstProfile)));
|
||||||
|
|
||||||
|
return lstProfile.Count;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion Server
|
#endregion Server
|
||||||
|
|
||||||
#region Batch add servers
|
#region Batch add servers
|
||||||
@@ -1039,16 +1084,16 @@ namespace ServiceLib.Handler
|
|||||||
/// <returns>成功导入的数量</returns>
|
/// <returns>成功导入的数量</returns>
|
||||||
private static async Task<int> AddBatchServersCommon(Config config, string strData, string subid, bool isSub)
|
private static async Task<int> AddBatchServersCommon(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(strData))
|
if (strData.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subFilter = string.Empty;
|
var subFilter = string.Empty;
|
||||||
//remove sub items
|
//remove sub items
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && subid.IsNotEmpty())
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
|
subFilter = (await AppHandler.Instance.GetSubItem(subid))?.Filter ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1077,7 +1122,7 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
|
|
||||||
//exist sub items //filter
|
//exist sub items //filter
|
||||||
if (isSub && Utils.IsNotEmpty(subid) && Utils.IsNotEmpty(subFilter))
|
if (isSub && subid.IsNotEmpty() && subFilter.IsNotEmpty())
|
||||||
{
|
{
|
||||||
if (!Regex.IsMatch(profileItem.Remarks, subFilter))
|
if (!Regex.IsMatch(profileItem.Remarks, subFilter))
|
||||||
{
|
{
|
||||||
@@ -1118,7 +1163,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub)
|
private static async Task<int> AddBatchServers4Custom(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(strData))
|
if (strData.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1140,9 +1185,9 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
if (lstProfiles != null && lstProfiles.Count > 0)
|
if (lstProfiles != null && lstProfiles.Count > 0)
|
||||||
{
|
{
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && subid.IsNotEmpty())
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
}
|
}
|
||||||
int count = 0;
|
int count = 0;
|
||||||
foreach (var it in lstProfiles)
|
foreach (var it in lstProfiles)
|
||||||
@@ -1191,14 +1236,14 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
profileItem = NaiveproxyFmt.ResolveFull(strData, subRemarks);
|
profileItem = NaiveproxyFmt.ResolveFull(strData, subRemarks);
|
||||||
}
|
}
|
||||||
if (profileItem is null || Utils.IsNullOrEmpty(profileItem.Address))
|
if (profileItem is null || profileItem.Address.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && subid.IsNotEmpty())
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
profileItem.Subid = subid;
|
profileItem.Subid = subid;
|
||||||
@@ -1216,14 +1261,14 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub)
|
private static async Task<int> AddBatchServers4SsSIP008(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(strData))
|
if (strData.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && subid.IsNotEmpty())
|
||||||
{
|
{
|
||||||
await RemoveServerViaSubid(config, subid, isSub);
|
await RemoveServersViaSubid(config, subid, isSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
|
var lstSsServer = ShadowsocksFmt.ResolveSip008(strData);
|
||||||
@@ -1248,13 +1293,13 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
public static async Task<int> AddBatchServers(Config config, string strData, string subid, bool isSub)
|
public static async Task<int> AddBatchServers(Config config, string strData, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(strData))
|
if (strData.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
List<ProfileItem>? lstOriSub = null;
|
List<ProfileItem>? lstOriSub = null;
|
||||||
ProfileItem? activeProfile = null;
|
ProfileItem? activeProfile = null;
|
||||||
if (isSub && Utils.IsNotEmpty(subid))
|
if (isSub && subid.IsNotEmpty())
|
||||||
{
|
{
|
||||||
lstOriSub = await AppHandler.Instance.ProfileItems(subid);
|
lstOriSub = await AppHandler.Instance.ProfileItems(subid);
|
||||||
activeProfile = lstOriSub?.FirstOrDefault(t => t.IndexId == config.IndexId);
|
activeProfile = lstOriSub?.FirstOrDefault(t => t.IndexId == config.IndexId);
|
||||||
@@ -1338,7 +1383,8 @@ namespace ServiceLib.Handler
|
|||||||
};
|
};
|
||||||
|
|
||||||
var uri = Utils.TryUri(url);
|
var uri = Utils.TryUri(url);
|
||||||
if (uri == null) return -1;
|
if (uri == null)
|
||||||
|
return -1;
|
||||||
//Do not allow http protocol
|
//Do not allow http protocol
|
||||||
if (url.StartsWith(Global.HttpProtocol) && !Utils.IsPrivateNetwork(uri.IdnHost))
|
if (url.StartsWith(Global.HttpProtocol) && !Utils.IsPrivateNetwork(uri.IdnHost))
|
||||||
{
|
{
|
||||||
@@ -1378,7 +1424,7 @@ namespace ServiceLib.Handler
|
|||||||
item.Memo = subItem.Memo;
|
item.Memo = subItem.Memo;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(item.Id))
|
if (item.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
item.Id = Utils.GetGuid(false);
|
item.Id = Utils.GetGuid(false);
|
||||||
|
|
||||||
@@ -1409,9 +1455,9 @@ namespace ServiceLib.Handler
|
|||||||
/// <param name="config"></param>
|
/// <param name="config"></param>
|
||||||
/// <param name="subid"></param>
|
/// <param name="subid"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<int> RemoveServerViaSubid(Config config, string subid, bool isSub)
|
public static async Task<int> RemoveServersViaSubid(Config config, string subid, bool isSub)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(subid))
|
if (subid.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1440,7 +1486,7 @@ namespace ServiceLib.Handler
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
await SQLiteHelper.Instance.DeleteAsync(item);
|
await SQLiteHelper.Instance.DeleteAsync(item);
|
||||||
await RemoveServerViaSubid(config, id, false);
|
await RemoveServersViaSubid(config, id, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1462,7 +1508,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
public static async Task<int> SaveRoutingItem(Config config, RoutingItem item)
|
public static async Task<int> SaveRoutingItem(Config config, RoutingItem item)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(item.Id))
|
if (item.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
item.Id = Utils.GetGuid(false);
|
item.Id = Utils.GetGuid(false);
|
||||||
}
|
}
|
||||||
@@ -1485,7 +1531,7 @@ namespace ServiceLib.Handler
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static async Task<int> AddBatchRoutingRules(RoutingItem routingItem, string strData)
|
public static async Task<int> AddBatchRoutingRules(RoutingItem routingItem, string strData)
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(strData))
|
if (strData.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -1503,7 +1549,7 @@ namespace ServiceLib.Handler
|
|||||||
routingItem.RuleNum = lstRules.Count;
|
routingItem.RuleNum = lstRules.Count;
|
||||||
routingItem.RuleSet = JsonUtils.Serialize(lstRules, false);
|
routingItem.RuleSet = JsonUtils.Serialize(lstRules, false);
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(routingItem.Id))
|
if (routingItem.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
routingItem.Id = Utils.GetGuid(false);
|
routingItem.Id = Utils.GetGuid(false);
|
||||||
}
|
}
|
||||||
@@ -1592,7 +1638,7 @@ namespace ServiceLib.Handler
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return await Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
public static async Task<int> SetDefaultRouting(Config config, RoutingItem routingItem)
|
||||||
@@ -1622,7 +1668,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
public static async Task<int> InitRouting(Config config, bool blImportAdvancedRules = false)
|
public static async Task<int> InitRouting(Config config, bool blImportAdvancedRules = false)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(config.ConstItem.RouteRulesTemplateSourceUrl))
|
if (config.ConstItem.RouteRulesTemplateSourceUrl.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
await InitBuiltinRouting(config, blImportAdvancedRules);
|
await InitBuiltinRouting(config, blImportAdvancedRules);
|
||||||
}
|
}
|
||||||
@@ -1638,7 +1684,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
var downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
var templateContent = await downloadHandle.TryDownloadString(config.ConstItem.RouteRulesTemplateSourceUrl, true, "");
|
var templateContent = await downloadHandle.TryDownloadString(config.ConstItem.RouteRulesTemplateSourceUrl, true, "");
|
||||||
if (string.IsNullOrEmpty(templateContent))
|
if (templateContent.IsNullOrEmpty())
|
||||||
return await InitBuiltinRouting(config, blImportAdvancedRules); // fallback
|
return await InitBuiltinRouting(config, blImportAdvancedRules); // fallback
|
||||||
|
|
||||||
var template = JsonUtils.Deserialize<RoutingTemplate>(templateContent);
|
var template = JsonUtils.Deserialize<RoutingTemplate>(templateContent);
|
||||||
@@ -1655,14 +1701,14 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
var item = template.RoutingItems[i];
|
var item = template.RoutingItems[i];
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(item.Url) && string.IsNullOrEmpty(item.RuleSet))
|
if (item.Url.IsNullOrEmpty() && item.RuleSet.IsNullOrEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var ruleSetsString = !string.IsNullOrEmpty(item.RuleSet)
|
var ruleSetsString = !item.RuleSet.IsNullOrEmpty()
|
||||||
? item.RuleSet
|
? item.RuleSet
|
||||||
: await downloadHandle.TryDownloadString(item.Url, true, "");
|
: await downloadHandle.TryDownloadString(item.Url, true, "");
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ruleSetsString))
|
if (ruleSetsString.IsNullOrEmpty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
item.Remarks = $"{template.Version}-{item.Remarks}";
|
item.Remarks = $"{template.Version}-{item.Remarks}";
|
||||||
@@ -1708,7 +1754,7 @@ namespace ServiceLib.Handler
|
|||||||
Url = string.Empty,
|
Url = string.Empty,
|
||||||
Sort = maxSort + 1,
|
Sort = maxSort + 1,
|
||||||
};
|
};
|
||||||
await AddBatchRoutingRules(item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
|
await AddBatchRoutingRules(item2, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "white"));
|
||||||
|
|
||||||
//Blacklist
|
//Blacklist
|
||||||
var item3 = new RoutingItem()
|
var item3 = new RoutingItem()
|
||||||
@@ -1717,7 +1763,7 @@ namespace ServiceLib.Handler
|
|||||||
Url = string.Empty,
|
Url = string.Empty,
|
||||||
Sort = maxSort + 2,
|
Sort = maxSort + 2,
|
||||||
};
|
};
|
||||||
await AddBatchRoutingRules(item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
|
await AddBatchRoutingRules(item3, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "black"));
|
||||||
|
|
||||||
//Global
|
//Global
|
||||||
var item1 = new RoutingItem()
|
var item1 = new RoutingItem()
|
||||||
@@ -1726,7 +1772,7 @@ namespace ServiceLib.Handler
|
|||||||
Url = string.Empty,
|
Url = string.Empty,
|
||||||
Sort = maxSort + 3,
|
Sort = maxSort + 3,
|
||||||
};
|
};
|
||||||
await AddBatchRoutingRules(item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));
|
await AddBatchRoutingRules(item1, EmbedUtils.GetEmbedText(Global.CustomRoutingFileName + "global"));
|
||||||
|
|
||||||
if (!blImportAdvancedRules)
|
if (!blImportAdvancedRules)
|
||||||
{
|
{
|
||||||
@@ -1774,7 +1820,7 @@ namespace ServiceLib.Handler
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNullOrEmpty(item.Id))
|
if (item.Id.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
item.Id = Utils.GetGuid(false);
|
item.Id = Utils.GetGuid(false);
|
||||||
}
|
}
|
||||||
@@ -1795,17 +1841,17 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
var downloadHandle = new DownloadService();
|
var downloadHandle = new DownloadService();
|
||||||
var templateContent = await downloadHandle.TryDownloadString(url, true, "");
|
var templateContent = await downloadHandle.TryDownloadString(url, true, "");
|
||||||
if (string.IsNullOrEmpty(templateContent))
|
if (templateContent.IsNullOrEmpty())
|
||||||
return currentItem;
|
return currentItem;
|
||||||
|
|
||||||
var template = JsonUtils.Deserialize<DNSItem>(templateContent);
|
var template = JsonUtils.Deserialize<DNSItem>(templateContent);
|
||||||
if (template == null)
|
if (template == null)
|
||||||
return currentItem;
|
return currentItem;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(template.NormalDNS))
|
if (!template.NormalDNS.IsNullOrEmpty())
|
||||||
template.NormalDNS = await downloadHandle.TryDownloadString(template.NormalDNS, true, "");
|
template.NormalDNS = await downloadHandle.TryDownloadString(template.NormalDNS, true, "");
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(template.TunDNS))
|
if (!template.TunDNS.IsNullOrEmpty())
|
||||||
template.TunDNS = await downloadHandle.TryDownloadString(template.TunDNS, true, "");
|
template.TunDNS = await downloadHandle.TryDownloadString(template.TunDNS, true, "");
|
||||||
|
|
||||||
template.Id = currentItem.Id;
|
template.Id = currentItem.Id;
|
||||||
@@ -1842,6 +1888,16 @@ namespace ServiceLib.Handler
|
|||||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json"));
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[1] + "v2ray.json"));
|
||||||
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[1] + "sing_box.json"));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case EPresetType.Iran:
|
||||||
|
config.ConstItem.GeoSourceUrl = Global.GeoFilesSources[2];
|
||||||
|
config.ConstItem.SrsSourceUrl = Global.SingboxRulesetSources[2];
|
||||||
|
config.ConstItem.RouteRulesTemplateSourceUrl = Global.RoutingRulesSources[2];
|
||||||
|
|
||||||
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.Xray, Global.DNSTemplateSources[2] + "v2ray.json"));
|
||||||
|
await SaveDNSItems(config, await GetExternalDNSItem(ECoreType.sing_box, Global.DNSTemplateSources[2] + "sing_box.json"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Core configuration file processing class
|
/// Core configuration file processing class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CoreConfigHandler
|
public class CoreConfigHandler
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "CoreConfigHandler";
|
||||||
|
|
||||||
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
|
public static async Task<RetResult> GenerateClientConfig(ProfileItem node, string? fileName)
|
||||||
{
|
{
|
||||||
var config = AppHandler.Instance.Config;
|
var config = AppHandler.Instance.Config;
|
||||||
@@ -31,7 +33,7 @@
|
|||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(fileName) && result.Data != null)
|
if (fileName.IsNotEmpty() && result.Data != null)
|
||||||
{
|
{
|
||||||
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
||||||
}
|
}
|
||||||
@@ -78,11 +80,11 @@
|
|||||||
|
|
||||||
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
ret.Msg = string.Format(ResUI.SuccessfulConfiguration, "");
|
||||||
ret.Success = true;
|
ret.Success = true;
|
||||||
return ret;
|
return await Task.FromResult(ret);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("GenerateClientCustomConfig", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -107,6 +109,30 @@
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<RetResult> GenerateClientSpeedtestConfig(Config config, ProfileItem node, ServerTestItem testItem, string fileName)
|
||||||
|
{
|
||||||
|
var result = new RetResult();
|
||||||
|
var initPort = AppHandler.Instance.GetLocalPort(EInboundProtocol.speedtest);
|
||||||
|
var port = Utils.GetFreePort(initPort + testItem.QueueNum);
|
||||||
|
testItem.Port = port;
|
||||||
|
|
||||||
|
if (AppHandler.Instance.GetCoreType(node, node.ConfigType) == ECoreType.sing_box)
|
||||||
|
{
|
||||||
|
result = await new CoreConfigSingboxService(config).GenerateClientSpeedtestConfig(node, port);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = await new CoreConfigV2rayService(config).GenerateClientSpeedtestConfig(node, port);
|
||||||
|
}
|
||||||
|
if (result.Success != true)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(fileName, result.Data.ToString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType)
|
public static async Task<RetResult> GenerateClientMultipleLoadConfig(Config config, string fileName, List<ProfileItem> selecteds, ECoreType coreType)
|
||||||
{
|
{
|
||||||
var result = new RetResult();
|
var result = new RetResult();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
@@ -13,26 +13,39 @@ namespace ServiceLib.Handler
|
|||||||
private Config _config;
|
private Config _config;
|
||||||
private Process? _process;
|
private Process? _process;
|
||||||
private Process? _processPre;
|
private Process? _processPre;
|
||||||
|
private int _linuxSudoPid = -1;
|
||||||
private Action<bool, string>? _updateFunc;
|
private Action<bool, string>? _updateFunc;
|
||||||
|
private const string _tag = "CoreHandler";
|
||||||
|
|
||||||
public async Task Init(Config config, Action<bool, string> updateFunc)
|
public async Task Init(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = updateFunc;
|
_updateFunc = updateFunc;
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable("V2RAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
Environment.SetEnvironmentVariable("XRAY_LOCATION_ASSET", Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||||
|
|
||||||
if (Utils.IsLinux())
|
//Copy the bin folder to the storage location (for init)
|
||||||
|
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
|
||||||
|
{
|
||||||
|
var fromPath = Utils.GetBaseDirectory("bin");
|
||||||
|
var toPath = Utils.GetBinPath("");
|
||||||
|
if (fromPath != toPath)
|
||||||
|
{
|
||||||
|
FileManager.CopyDirectory(fromPath, toPath, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Utils.IsNonWindows())
|
||||||
{
|
{
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo();
|
||||||
foreach (var it in coreInfo)
|
foreach (var it in coreInfo)
|
||||||
{
|
{
|
||||||
if (it.CoreType == ECoreType.v2rayN)
|
if (it.CoreType == ECoreType.v2rayN)
|
||||||
{
|
{
|
||||||
if (Utils.UpgradeAppExists(out var fileName))
|
if (Utils.UpgradeAppExists(out var upgradeFileName))
|
||||||
{
|
{
|
||||||
await Utils.SetLinuxChmod(fileName);
|
await Utils.SetLinuxChmod(upgradeFileName);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -53,60 +66,88 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
if (node == null)
|
if (node == null)
|
||||||
{
|
{
|
||||||
ShowMsg(false, ResUI.CheckServerSettings);
|
UpdateFunc(false, ResUI.CheckServerSettings);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileName = Utils.GetConfigPath(Global.CoreConfigFileName);
|
var fileName = Utils.GetBinConfigPath(Global.CoreConfigFileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
var result = await CoreConfigHandler.GenerateClientConfig(node, fileName);
|
||||||
if (result.Success != true)
|
if (result.Success != true)
|
||||||
{
|
{
|
||||||
ShowMsg(true, result.Msg);
|
UpdateFunc(true, result.Msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
UpdateFunc(false, $"{node.GetSummary()}");
|
||||||
ShowMsg(true, $"{node.GetSummary()}");
|
UpdateFunc(false, $"{Utils.GetRuntimeInfo()}");
|
||||||
ShowMsg(false, $"{Environment.OSVersion} - {(Environment.Is64BitOperatingSystem ? 64 : 32)}");
|
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
|
||||||
await CoreStop();
|
await CoreStop();
|
||||||
await Task.Delay(100);
|
await Task.Delay(100);
|
||||||
await CoreStart(node);
|
|
||||||
|
|
||||||
//In tun mode, do a delay check and restart the core
|
if (Utils.IsWindows() && _config.TunModeItem.EnableTun)
|
||||||
//if (_config.tunModeItem.enableTun)
|
{
|
||||||
//{
|
await Task.Delay(100);
|
||||||
// Observable.Range(1, 1)
|
await WindowsUtils.RemoveTunDevice();
|
||||||
// .Delay(TimeSpan.FromSeconds(15))
|
}
|
||||||
// .Subscribe(x =>
|
|
||||||
// {
|
await CoreStart(node);
|
||||||
// {
|
await CoreStartPreService(node);
|
||||||
// if (_process == null || _process.HasExited)
|
if (_process != null)
|
||||||
// {
|
{
|
||||||
// CoreStart(node);
|
UpdateFunc(true, $"{node.GetSummary()}");
|
||||||
// ShowMsg(false, "Tun mode restart the core once");
|
|
||||||
// Logging.SaveLog("Tun mode restart the core once");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
public async Task<int> LoadCoreConfigSpeedtest(List<ServerTestItem> selecteds)
|
||||||
{
|
{
|
||||||
var pid = -1;
|
|
||||||
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
var coreType = selecteds.Exists(t => t.ConfigType is EConfigType.Hysteria2 or EConfigType.TUIC or EConfigType.WireGuard) ? ECoreType.sing_box : ECoreType.Xray;
|
||||||
var configPath = Utils.GetConfigPath(Global.CoreSpeedtestConfigFileName);
|
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
||||||
|
var configPath = Utils.GetBinConfigPath(fileName);
|
||||||
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, configPath, selecteds, coreType);
|
||||||
ShowMsg(false, result.Msg);
|
UpdateFunc(false, result.Msg);
|
||||||
if (result.Success)
|
if (result.Success != true)
|
||||||
{
|
{
|
||||||
ShowMsg(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
return -1;
|
||||||
ShowMsg(false, configPath);
|
|
||||||
pid = await CoreStartSpeedtest(configPath, coreType);
|
|
||||||
}
|
}
|
||||||
return pid;
|
|
||||||
|
UpdateFunc(false, string.Format(ResUI.StartService, DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")));
|
||||||
|
UpdateFunc(false, configPath);
|
||||||
|
|
||||||
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
|
var proc = await RunProcess(coreInfo, fileName, true, false);
|
||||||
|
if (proc is null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> LoadCoreConfigSpeedtest(ServerTestItem testItem)
|
||||||
|
{
|
||||||
|
var node = await AppHandler.Instance.GetProfileItem(testItem.IndexId);
|
||||||
|
if (node is null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileName = string.Format(Global.CoreSpeedtestConfigFileName, Utils.GetGuid(false));
|
||||||
|
var configPath = Utils.GetBinConfigPath(fileName);
|
||||||
|
var result = await CoreConfigHandler.GenerateClientSpeedtestConfig(_config, node, testItem, configPath);
|
||||||
|
if (result.Success != true)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
|
var proc = await RunProcess(coreInfo, fileName, true, false);
|
||||||
|
if (proc is null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CoreStop()
|
public async Task CoreStop()
|
||||||
@@ -115,64 +156,33 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
if (_process != null)
|
if (_process != null)
|
||||||
{
|
{
|
||||||
await KillProcess(_process);
|
await ProcUtils.ProcessKill(_process, true);
|
||||||
_process.Dispose();
|
|
||||||
_process = null;
|
_process = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_processPre != null)
|
if (_processPre != null)
|
||||||
{
|
{
|
||||||
await KillProcess(_processPre);
|
await ProcUtils.ProcessKill(_processPre, true);
|
||||||
_processPre.Dispose();
|
|
||||||
_processPre = null;
|
_processPre = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CoreStopPid(int pid)
|
if (_linuxSudoPid > 0)
|
||||||
{
|
{
|
||||||
try
|
await KillProcessAsLinuxSudo();
|
||||||
{
|
}
|
||||||
var _p = Process.GetProcessById(pid);
|
_linuxSudoPid = -1;
|
||||||
await KillProcess(_p);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Private
|
#region Private
|
||||||
|
|
||||||
private string CoreFindExe(CoreInfo coreInfo)
|
|
||||||
{
|
|
||||||
var fileName = string.Empty;
|
|
||||||
foreach (var name in coreInfo.CoreExes)
|
|
||||||
{
|
|
||||||
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
|
|
||||||
if (File.Exists(vName))
|
|
||||||
{
|
|
||||||
fileName = vName;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
|
||||||
{
|
|
||||||
var msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo.CoreType.ToString()), string.Join(", ", coreInfo.CoreExes.ToArray()), coreInfo.Url);
|
|
||||||
Logging.SaveLog(msg);
|
|
||||||
ShowMsg(false, msg);
|
|
||||||
}
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task CoreStart(ProfileItem node)
|
private async Task CoreStart(ProfileItem node)
|
||||||
{
|
{
|
||||||
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
var coreType = _config.RunningCoreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
_config.RunningCoreType = coreType;
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
||||||
|
|
||||||
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
var displayLog = node.ConfigType != EConfigType.Custom || node.DisplayLog;
|
||||||
@@ -182,74 +192,34 @@ namespace ServiceLib.Handler
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_process = proc;
|
_process = proc;
|
||||||
|
}
|
||||||
|
|
||||||
//start a pre service
|
private async Task CoreStartPreService(ProfileItem node)
|
||||||
|
{
|
||||||
if (_process != null && !_process.HasExited)
|
if (_process != null && !_process.HasExited)
|
||||||
{
|
{
|
||||||
ProfileItem? itemSocks = null;
|
var coreType = AppHandler.Instance.GetCoreType(node, node.ConfigType);
|
||||||
var preCoreType = ECoreType.sing_box;
|
var itemSocks = await ConfigHandler.GetPreSocksItem(_config, node, coreType);
|
||||||
if (node.ConfigType != EConfigType.Custom && coreType != ECoreType.sing_box && _config.TunModeItem.EnableTun)
|
|
||||||
{
|
|
||||||
itemSocks = new ProfileItem()
|
|
||||||
{
|
|
||||||
CoreType = preCoreType,
|
|
||||||
ConfigType = EConfigType.SOCKS,
|
|
||||||
Address = Global.Loopback,
|
|
||||||
Sni = node.Address, //Tun2SocksAddress
|
|
||||||
Port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else if ((node.ConfigType == EConfigType.Custom && node.PreSocksPort > 0))
|
|
||||||
{
|
|
||||||
preCoreType = _config.TunModeItem.EnableTun ? ECoreType.sing_box : ECoreType.Xray;
|
|
||||||
itemSocks = new ProfileItem()
|
|
||||||
{
|
|
||||||
CoreType = preCoreType,
|
|
||||||
ConfigType = EConfigType.SOCKS,
|
|
||||||
Address = Global.Loopback,
|
|
||||||
Port = node.PreSocksPort.Value,
|
|
||||||
};
|
|
||||||
_config.RunningCoreType = preCoreType;
|
|
||||||
}
|
|
||||||
if (itemSocks != null)
|
if (itemSocks != null)
|
||||||
{
|
{
|
||||||
var fileName2 = Utils.GetConfigPath(Global.CorePreConfigFileName);
|
var preCoreType = itemSocks.CoreType ?? ECoreType.sing_box;
|
||||||
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName2);
|
var fileName = Utils.GetBinConfigPath(Global.CorePreConfigFileName);
|
||||||
|
var result = await CoreConfigHandler.GenerateClientConfig(itemSocks, fileName);
|
||||||
if (result.Success)
|
if (result.Success)
|
||||||
{
|
{
|
||||||
var coreInfo2 = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(preCoreType);
|
||||||
var proc2 = await RunProcess(coreInfo2, Global.CorePreConfigFileName, true, true);
|
var proc = await RunProcess(coreInfo, Global.CorePreConfigFileName, true, true);
|
||||||
if (proc2 is not null)
|
|
||||||
{
|
|
||||||
_processPre = proc2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<int> CoreStartSpeedtest(string configPath, ECoreType coreType)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var coreInfo = CoreInfoHandler.Instance.GetCoreInfo(coreType);
|
|
||||||
var proc = await RunProcess(coreInfo, Global.CoreSpeedtestConfigFileName, true, false);
|
|
||||||
if (proc is null)
|
if (proc is null)
|
||||||
{
|
{
|
||||||
return -1;
|
return;
|
||||||
|
}
|
||||||
|
_processPre = proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return proc.Id;
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logging.SaveLog(ex.Message, ex);
|
|
||||||
ShowMsg(false, ex.Message);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ShowMsg(bool notify, string msg)
|
private void UpdateFunc(bool notify, string msg)
|
||||||
{
|
{
|
||||||
_updateFunc?.Invoke(notify, msg);
|
_updateFunc?.Invoke(notify, msg);
|
||||||
}
|
}
|
||||||
@@ -258,7 +228,7 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
return _config.TunModeItem.EnableTun
|
return _config.TunModeItem.EnableTun
|
||||||
&& eCoreType == ECoreType.sing_box
|
&& eCoreType == ECoreType.sing_box
|
||||||
&& Utils.IsLinux()
|
&& (Utils.IsNonWindows())
|
||||||
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
//&& _config.TunModeItem.LinuxSudoPwd.IsNotEmpty()
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
@@ -267,11 +237,12 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
#region Process
|
#region Process
|
||||||
|
|
||||||
private async Task<Process?> RunProcess(CoreInfo coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
|
private async Task<Process?> RunProcess(CoreInfo? coreInfo, string configPath, bool displayLog, bool mayNeedSudo)
|
||||||
{
|
{
|
||||||
var fileName = CoreFindExe(coreInfo);
|
var fileName = CoreInfoHandler.Instance.GetCoreExecFile(coreInfo, out var msg);
|
||||||
if (Utils.IsNullOrEmpty(fileName))
|
if (fileName.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
|
UpdateFunc(false, msg);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,8 +253,8 @@ namespace ServiceLib.Handler
|
|||||||
StartInfo = new()
|
StartInfo = new()
|
||||||
{
|
{
|
||||||
FileName = fileName,
|
FileName = fileName,
|
||||||
Arguments = string.Format(coreInfo.Arguments, configPath),
|
Arguments = string.Format(coreInfo.Arguments, coreInfo.AbsolutePath ? Utils.GetBinConfigPath(configPath).AppendQuotes() : configPath),
|
||||||
WorkingDirectory = Utils.GetConfigPath(),
|
WorkingDirectory = Utils.GetBinConfigPath(),
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
RedirectStandardOutput = displayLog,
|
RedirectStandardOutput = displayLog,
|
||||||
RedirectStandardError = displayLog,
|
RedirectStandardError = displayLog,
|
||||||
@@ -296,27 +267,22 @@ namespace ServiceLib.Handler
|
|||||||
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
var isNeedSudo = mayNeedSudo && IsNeedSudo(coreInfo.CoreType);
|
||||||
if (isNeedSudo)
|
if (isNeedSudo)
|
||||||
{
|
{
|
||||||
await RunProcessAsLinuxRoot(proc, fileName, coreInfo, configPath);
|
await RunProcessAsLinuxSudo(proc, fileName, coreInfo, configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var startUpErrorMessage = new StringBuilder();
|
|
||||||
var startUpSuccessful = false;
|
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
proc.OutputDataReceived += (sender, e) =>
|
proc.OutputDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(e.Data)) return;
|
if (e.Data.IsNullOrEmpty())
|
||||||
ShowMsg(false, e.Data + Environment.NewLine);
|
return;
|
||||||
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
};
|
};
|
||||||
proc.ErrorDataReceived += (sender, e) =>
|
proc.ErrorDataReceived += (sender, e) =>
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(e.Data)) return;
|
if (e.Data.IsNullOrEmpty())
|
||||||
ShowMsg(false, e.Data + Environment.NewLine);
|
return;
|
||||||
|
UpdateFunc(false, e.Data + Environment.NewLine);
|
||||||
if (!startUpSuccessful)
|
|
||||||
{
|
|
||||||
startUpErrorMessage.Append(e.Data + Environment.NewLine);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
proc.Start();
|
proc.Start();
|
||||||
@@ -329,6 +295,8 @@ namespace ServiceLib.Handler
|
|||||||
await Task.Delay(10);
|
await Task.Delay(10);
|
||||||
await proc.StandardInput.WriteLineAsync(pwd);
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
}
|
}
|
||||||
|
if (isNeedSudo)
|
||||||
|
_linuxSudoPid = proc.Id;
|
||||||
|
|
||||||
if (displayLog)
|
if (displayLog)
|
||||||
{
|
{
|
||||||
@@ -336,86 +304,106 @@ namespace ServiceLib.Handler
|
|||||||
proc.BeginErrorReadLine();
|
proc.BeginErrorReadLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proc.WaitForExit(1000))
|
await Task.Delay(500);
|
||||||
{
|
|
||||||
proc.CancelErrorRead();
|
|
||||||
throw new Exception(displayLog ? startUpErrorMessage.ToString() : "启动进程失败并退出 (Failed to start the process and exited)");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
startUpSuccessful = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
AppHandler.Instance.AddProcess(proc.Handle);
|
AppHandler.Instance.AddProcess(proc.Handle);
|
||||||
|
if (proc is null or { HasExited: true })
|
||||||
|
{
|
||||||
|
throw new Exception(ResUI.FailedToRunCore);
|
||||||
|
}
|
||||||
return proc;
|
return proc;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
ShowMsg(true, ex.Message);
|
UpdateFunc(mayNeedSudo, ex.Message);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunProcessAsLinuxRoot(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
#endregion Process
|
||||||
|
|
||||||
|
#region Linux
|
||||||
|
|
||||||
|
private async Task RunProcessAsLinuxSudo(Process proc, string fileName, CoreInfo coreInfo, string configPath)
|
||||||
{
|
{
|
||||||
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetConfigPath(configPath).AppendQuotes())}";
|
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
|
||||||
|
|
||||||
//Prefer shell scripts
|
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh");
|
||||||
var shFilePath = Utils.GetBinPath("run_as_root.sh");
|
proc.StartInfo.FileName = shFilePath;
|
||||||
File.Delete(shFilePath);
|
proc.StartInfo.Arguments = "";
|
||||||
var sb = new StringBuilder();
|
proc.StartInfo.WorkingDirectory = "";
|
||||||
sb.AppendLine("#!/bin/sh");
|
|
||||||
sb.AppendLine(cmdLine);
|
|
||||||
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
|
||||||
await Utils.SetLinuxChmod(shFilePath);
|
|
||||||
|
|
||||||
//Replace command
|
|
||||||
var args = File.Exists(shFilePath) ? shFilePath : cmdLine;
|
|
||||||
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
{
|
{
|
||||||
proc.StartInfo.FileName = $"/bin/sudo";
|
|
||||||
proc.StartInfo.Arguments = $"-S {args}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
proc.StartInfo.FileName = $"/bin/pkexec";
|
|
||||||
proc.StartInfo.Arguments = $"{args}";
|
|
||||||
}
|
|
||||||
proc.StartInfo.WorkingDirectory = null;
|
|
||||||
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
proc.StartInfo.StandardInputEncoding = Encoding.UTF8;
|
||||||
proc.StartInfo.RedirectStandardInput = true;
|
proc.StartInfo.RedirectStandardInput = true;
|
||||||
Logging.SaveLog(proc.StartInfo.Arguments);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task KillProcess(Process? proc)
|
private async Task KillProcessAsLinuxSudo()
|
||||||
{
|
{
|
||||||
if (proc is null)
|
var cmdLine = $"kill {_linuxSudoPid}";
|
||||||
|
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh");
|
||||||
|
Process proc = new()
|
||||||
{
|
{
|
||||||
return;
|
StartInfo = new()
|
||||||
|
{
|
||||||
|
FileName = shFilePath,
|
||||||
|
UseShellExecute = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
StandardInputEncoding = Encoding.UTF8,
|
||||||
|
RedirectStandardInput = true
|
||||||
}
|
}
|
||||||
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(1));
|
};
|
||||||
try
|
proc.Start();
|
||||||
{
|
|
||||||
await proc.WaitForExitAsync(timeout.Token);
|
if (_config.TunModeItem.LinuxSudoPwd.IsNotEmpty())
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
proc.Kill();
|
|
||||||
}
|
|
||||||
if (!proc.HasExited)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await proc.WaitForExitAsync(timeout.Token);
|
var pwd = DesUtils.Decrypt(_config.TunModeItem.LinuxSudoPwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
|
await Task.Delay(10);
|
||||||
|
await proc.StandardInput.WriteLineAsync(pwd);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
proc.Kill();
|
// ignored
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion Process
|
var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10));
|
||||||
|
await proc.WaitForExitAsync(timeout.Token);
|
||||||
|
await Task.Delay(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
|
||||||
|
{
|
||||||
|
//Shell scripts
|
||||||
|
var shFilePath = Utils.GetBinConfigPath(AppHandler.Instance.IsAdministrator ? "root_" + fileName : fileName);
|
||||||
|
File.Delete(shFilePath);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine("#!/bin/sh");
|
||||||
|
if (AppHandler.Instance.IsAdministrator)
|
||||||
|
{
|
||||||
|
sb.AppendLine($"{cmdLine}");
|
||||||
|
}
|
||||||
|
else if (_config.TunModeItem.LinuxSudoPwd.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
sb.AppendLine($"pkexec {cmdLine}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.AppendLine($"sudo -S {cmdLine}");
|
||||||
|
}
|
||||||
|
|
||||||
|
await File.WriteAllTextAsync(shFilePath, sb.ToString());
|
||||||
|
await Utils.SetLinuxChmod(shFilePath);
|
||||||
|
Logging.SaveLog(shFilePath);
|
||||||
|
|
||||||
|
return shFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Linux
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
public sealed class CoreInfoHandler
|
public sealed class CoreInfoHandler
|
||||||
{
|
{
|
||||||
@@ -29,143 +29,190 @@
|
|||||||
return _coreInfo ?? [];
|
return _coreInfo ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitCoreInfo()
|
public string GetCoreExecFile(CoreInfo? coreInfo, out string msg)
|
||||||
{
|
{
|
||||||
_coreInfo = [];
|
var fileName = string.Empty;
|
||||||
|
msg = string.Empty;
|
||||||
_coreInfo.Add(new CoreInfo
|
foreach (var name in coreInfo?.CoreExes)
|
||||||
{
|
{
|
||||||
CoreType = ECoreType.v2rayN,
|
var vName = Utils.GetBinPath(Utils.GetExeName(name), coreInfo.CoreType.ToString());
|
||||||
Url = Global.NUrl,
|
if (File.Exists(vName))
|
||||||
ReleaseApiUrl = Global.NUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
DownloadUrlWin64 = Global.NUrl + "/download/{0}/v2rayN-windows-64.zip",
|
|
||||||
DownloadUrlWinArm64 = Global.NUrl + "/download/{0}/v2rayN-windows-arm64.zip",
|
|
||||||
DownloadUrlLinux64 = Global.NUrl + "/download/{0}/v2rayN-linux-64.zip",
|
|
||||||
DownloadUrlLinuxArm64 = Global.NUrl + "/download/{0}/v2rayN-linux-arm64.zip",
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
{
|
||||||
CoreType = ECoreType.v2fly,
|
fileName = vName;
|
||||||
CoreExes = new List<string> { "wv2ray", "v2ray" },
|
break;
|
||||||
Arguments = "",
|
}
|
||||||
Url = Global.V2flyCoreUrl,
|
}
|
||||||
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
if (fileName.IsNullOrEmpty())
|
||||||
Match = "V2Ray",
|
|
||||||
VersionArg = "-version",
|
|
||||||
RedirectInfo = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
{
|
||||||
CoreType = ECoreType.v2fly_v5,
|
msg = string.Format(ResUI.NotFoundCore, Utils.GetBinPath("", coreInfo?.CoreType.ToString()), coreInfo?.CoreExes?.LastOrDefault(), coreInfo?.Url);
|
||||||
CoreExes = new List<string> { "v2ray" },
|
Logging.SaveLog(msg);
|
||||||
Arguments = "run -c config.json -format jsonv5",
|
}
|
||||||
Url = Global.V2flyCoreUrl,
|
return fileName;
|
||||||
ReleaseApiUrl = Global.V2flyCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
Match = "V2Ray",
|
|
||||||
VersionArg = "version",
|
|
||||||
RedirectInfo = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.Xray,
|
|
||||||
CoreExes = new List<string> { "xray", "wxray" },
|
|
||||||
Arguments = "run -c {0}",
|
|
||||||
Url = Global.XrayCoreUrl,
|
|
||||||
ReleaseApiUrl = Global.XrayCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
DownloadUrlWin64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-64.zip",
|
|
||||||
DownloadUrlWinArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
|
||||||
DownloadUrlLinux64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-64.zip",
|
|
||||||
DownloadUrlLinuxArm64 = Global.XrayCoreUrl + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
|
||||||
Match = "Xray",
|
|
||||||
VersionArg = "-version",
|
|
||||||
RedirectInfo = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.mihomo,
|
|
||||||
CoreExes = new List<string> { "mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "mihomo", "clash" },
|
|
||||||
Arguments = "-f config.json" + PortableMode(),
|
|
||||||
Url = Global.MihomoCoreUrl,
|
|
||||||
ReleaseApiUrl = Global.MihomoCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
DownloadUrlWin64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
|
||||||
DownloadUrlWinArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
|
||||||
DownloadUrlLinux64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
|
||||||
DownloadUrlLinuxArm64 = Global.MihomoCoreUrl + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
|
||||||
Match = "Mihomo",
|
|
||||||
VersionArg = "-v",
|
|
||||||
RedirectInfo = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.hysteria,
|
|
||||||
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria" },
|
|
||||||
Arguments = "",
|
|
||||||
Url = Global.HysteriaCoreUrl,
|
|
||||||
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
RedirectInfo = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.naiveproxy,
|
|
||||||
CoreExes = new List<string> { "naiveproxy", "naive" },
|
|
||||||
Arguments = "config.json",
|
|
||||||
Url = Global.NaiveproxyCoreUrl,
|
|
||||||
RedirectInfo = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.tuic,
|
|
||||||
CoreExes = new List<string> { "tuic-client", "tuic" },
|
|
||||||
Arguments = "-c config.json",
|
|
||||||
Url = Global.TuicCoreUrl,
|
|
||||||
RedirectInfo = true,
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.sing_box,
|
|
||||||
CoreExes = new List<string> { "sing-box-client", "sing-box" },
|
|
||||||
Arguments = "run -c {0} --disable-color",
|
|
||||||
Url = Global.SingboxCoreUrl,
|
|
||||||
RedirectInfo = true,
|
|
||||||
ReleaseApiUrl = Global.SingboxCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
DownloadUrlWin64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
|
||||||
DownloadUrlWinArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
|
||||||
DownloadUrlLinux64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
|
||||||
DownloadUrlLinuxArm64 = Global.SingboxCoreUrl + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
|
||||||
Match = "sing-box",
|
|
||||||
VersionArg = "version",
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.juicity,
|
|
||||||
CoreExes = new List<string> { "juicity-client", "juicity" },
|
|
||||||
Arguments = "run -c config.json",
|
|
||||||
Url = Global.JuicityCoreUrl
|
|
||||||
});
|
|
||||||
|
|
||||||
_coreInfo.Add(new CoreInfo
|
|
||||||
{
|
|
||||||
CoreType = ECoreType.hysteria2,
|
|
||||||
CoreExes = new List<string> { "hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria" },
|
|
||||||
Arguments = "",
|
|
||||||
Url = Global.HysteriaCoreUrl,
|
|
||||||
ReleaseApiUrl = Global.HysteriaCoreUrl.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
|
||||||
RedirectInfo = true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string PortableMode()
|
private void InitCoreInfo()
|
||||||
|
{
|
||||||
|
var urlN = GetCoreUrl(ECoreType.v2rayN);
|
||||||
|
var urlXray = GetCoreUrl(ECoreType.Xray);
|
||||||
|
var urlMihomo = GetCoreUrl(ECoreType.mihomo);
|
||||||
|
var urlSingbox = GetCoreUrl(ECoreType.sing_box);
|
||||||
|
|
||||||
|
_coreInfo =
|
||||||
|
[
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.v2rayN,
|
||||||
|
Url = GetCoreUrl(ECoreType.v2rayN),
|
||||||
|
ReleaseApiUrl = urlN.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
DownloadUrlWin64 = urlN + "/download/{0}/v2rayN-windows-64.zip",
|
||||||
|
DownloadUrlWinArm64 = urlN + "/download/{0}/v2rayN-windows-arm64.zip",
|
||||||
|
DownloadUrlLinux64 = urlN + "/download/{0}/v2rayN-linux-64.zip",
|
||||||
|
DownloadUrlLinuxArm64 = urlN + "/download/{0}/v2rayN-linux-arm64.zip",
|
||||||
|
DownloadUrlOSX64 = urlN + "/download/{0}/v2rayN-macos-64.zip",
|
||||||
|
DownloadUrlOSXArm64 = urlN + "/download/{0}/v2rayN-macos-arm64.zip",
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.v2fly,
|
||||||
|
CoreExes = ["v2ray"],
|
||||||
|
Arguments = "{0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.v2fly),
|
||||||
|
Match = "V2Ray",
|
||||||
|
VersionArg = "-version",
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.v2fly_v5,
|
||||||
|
CoreExes = ["v2ray"],
|
||||||
|
Arguments = "run -c {0} -format jsonv5",
|
||||||
|
Url = GetCoreUrl(ECoreType.v2fly_v5),
|
||||||
|
Match = "V2Ray",
|
||||||
|
VersionArg = "version",
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.Xray,
|
||||||
|
CoreExes = ["xray"],
|
||||||
|
Arguments = "run -c {0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.Xray),
|
||||||
|
ReleaseApiUrl = urlXray.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
DownloadUrlWin64 = urlXray + "/download/{0}/Xray-windows-64.zip",
|
||||||
|
DownloadUrlWinArm64 = urlXray + "/download/{0}/Xray-windows-arm64-v8a.zip",
|
||||||
|
DownloadUrlLinux64 = urlXray + "/download/{0}/Xray-linux-64.zip",
|
||||||
|
DownloadUrlLinuxArm64 = urlXray + "/download/{0}/Xray-linux-arm64-v8a.zip",
|
||||||
|
DownloadUrlOSX64 = urlXray + "/download/{0}/Xray-macos-64.zip",
|
||||||
|
DownloadUrlOSXArm64 = urlXray + "/download/{0}/Xray-macos-arm64-v8a.zip",
|
||||||
|
Match = "Xray",
|
||||||
|
VersionArg = "-version",
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.mihomo,
|
||||||
|
CoreExes = ["mihomo-windows-amd64-compatible", "mihomo-windows-amd64", "mihomo-linux-amd64", "clash", "mihomo"],
|
||||||
|
Arguments = "-f {0}" + PortableMode(),
|
||||||
|
Url = GetCoreUrl(ECoreType.mihomo),
|
||||||
|
ReleaseApiUrl = urlMihomo.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
DownloadUrlWin64 = urlMihomo + "/download/{0}/mihomo-windows-amd64-compatible-{0}.zip",
|
||||||
|
DownloadUrlWinArm64 = urlMihomo + "/download/{0}/mihomo-windows-arm64-{0}.zip",
|
||||||
|
DownloadUrlLinux64 = urlMihomo + "/download/{0}/mihomo-linux-amd64-compatible-{0}.gz",
|
||||||
|
DownloadUrlLinuxArm64 = urlMihomo + "/download/{0}/mihomo-linux-arm64-{0}.gz",
|
||||||
|
DownloadUrlOSX64 = urlMihomo + "/download/{0}/mihomo-darwin-amd64-compatible-{0}.gz",
|
||||||
|
DownloadUrlOSXArm64 = urlMihomo + "/download/{0}/mihomo-darwin-arm64-{0}.gz",
|
||||||
|
Match = "Mihomo",
|
||||||
|
VersionArg = "-v",
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.hysteria,
|
||||||
|
CoreExes = ["hysteria"],
|
||||||
|
Arguments = "",
|
||||||
|
Url = GetCoreUrl(ECoreType.hysteria),
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.naiveproxy,
|
||||||
|
CoreExes = [ "naive", "naiveproxy"],
|
||||||
|
Arguments = "{0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.naiveproxy),
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.tuic,
|
||||||
|
CoreExes = ["tuic-client", "tuic"],
|
||||||
|
Arguments = "-c {0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.tuic),
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.sing_box,
|
||||||
|
CoreExes = ["sing-box-client", "sing-box"],
|
||||||
|
Arguments = "run -c {0} --disable-color",
|
||||||
|
Url = GetCoreUrl(ECoreType.sing_box),
|
||||||
|
|
||||||
|
ReleaseApiUrl = urlSingbox.Replace(Global.GithubUrl, Global.GithubApiUrl),
|
||||||
|
DownloadUrlWin64 = urlSingbox + "/download/{0}/sing-box-{1}-windows-amd64.zip",
|
||||||
|
DownloadUrlWinArm64 = urlSingbox + "/download/{0}/sing-box-{1}-windows-arm64.zip",
|
||||||
|
DownloadUrlLinux64 = urlSingbox + "/download/{0}/sing-box-{1}-linux-amd64.tar.gz",
|
||||||
|
DownloadUrlLinuxArm64 = urlSingbox + "/download/{0}/sing-box-{1}-linux-arm64.tar.gz",
|
||||||
|
DownloadUrlOSX64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-amd64.tar.gz",
|
||||||
|
DownloadUrlOSXArm64 = urlSingbox + "/download/{0}/sing-box-{1}-darwin-arm64.tar.gz",
|
||||||
|
Match = "sing-box",
|
||||||
|
VersionArg = "version",
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.juicity,
|
||||||
|
CoreExes = ["juicity-client", "juicity"],
|
||||||
|
Arguments = "run -c {0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.juicity)
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.hysteria2,
|
||||||
|
CoreExes = ["hysteria-windows-amd64", "hysteria-linux-amd64", "hysteria"],
|
||||||
|
Arguments = "",
|
||||||
|
Url = GetCoreUrl(ECoreType.hysteria2),
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.brook,
|
||||||
|
CoreExes = ["brook_windows_amd64", "brook_linux_amd64", "brook"],
|
||||||
|
Arguments = " {0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.brook),
|
||||||
|
AbsolutePath = true,
|
||||||
|
},
|
||||||
|
|
||||||
|
new CoreInfo
|
||||||
|
{
|
||||||
|
CoreType = ECoreType.overtls,
|
||||||
|
CoreExes = [ "overtls-bin", "overtls"],
|
||||||
|
Arguments = "-r client -c {0}",
|
||||||
|
Url = GetCoreUrl(ECoreType.overtls),
|
||||||
|
AbsolutePath = false,
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string PortableMode()
|
||||||
{
|
{
|
||||||
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
|
return $" -d {Utils.GetBinPath("").AppendQuotes()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string GetCoreUrl(ECoreType eCoreType)
|
||||||
|
{
|
||||||
|
return $"{Global.GithubUrl}/{Global.CoreUrls[eCoreType]}/releases";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
|
||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
@@ -16,12 +16,12 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
|
|
||||||
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
protected static int GetStdTransport(ProfileItem item, string? securityDef, ref Dictionary<string, string> dicQuery)
|
||||||
{
|
{
|
||||||
if (Utils.IsNotEmpty(item.Flow))
|
if (item.Flow.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("flow", item.Flow);
|
dicQuery.Add("flow", item.Flow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utils.IsNotEmpty(item.StreamSecurity))
|
if (item.StreamSecurity.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("security", item.StreamSecurity);
|
dicQuery.Add("security", item.StreamSecurity);
|
||||||
}
|
}
|
||||||
@@ -32,27 +32,27 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
dicQuery.Add("security", securityDef);
|
dicQuery.Add("security", securityDef);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Sni))
|
if (item.Sni.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("sni", item.Sni);
|
dicQuery.Add("sni", item.Sni);
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Alpn))
|
if (item.Alpn.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Fingerprint))
|
if (item.Fingerprint.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("fp", Utils.UrlEncode(item.Fingerprint));
|
dicQuery.Add("fp", Utils.UrlEncode(item.Fingerprint));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.PublicKey))
|
if (item.PublicKey.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("pbk", Utils.UrlEncode(item.PublicKey));
|
dicQuery.Add("pbk", Utils.UrlEncode(item.PublicKey));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.ShortId))
|
if (item.ShortId.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("sid", Utils.UrlEncode(item.ShortId));
|
dicQuery.Add("sid", Utils.UrlEncode(item.ShortId));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.SpiderX))
|
if (item.SpiderX.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
|
dicQuery.Add("spx", Utils.UrlEncode(item.SpiderX));
|
||||||
}
|
}
|
||||||
@@ -61,21 +61,21 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
dicQuery.Add("allowInsecure", "1");
|
dicQuery.Add("allowInsecure", "1");
|
||||||
}
|
}
|
||||||
|
|
||||||
dicQuery.Add("type", Utils.IsNotEmpty(item.Network) ? item.Network : nameof(ETransport.tcp));
|
dicQuery.Add("type", item.Network.IsNotEmpty() ? item.Network : nameof(ETransport.tcp));
|
||||||
|
|
||||||
switch (item.Network)
|
switch (item.Network)
|
||||||
{
|
{
|
||||||
case nameof(ETransport.tcp):
|
case nameof(ETransport.tcp):
|
||||||
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
|
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
|
||||||
if (Utils.IsNotEmpty(item.RequestHost))
|
if (item.RequestHost.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.kcp):
|
case nameof(ETransport.kcp):
|
||||||
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
|
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
|
||||||
if (Utils.IsNotEmpty(item.Path))
|
if (item.Path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("seed", Utils.UrlEncode(item.Path));
|
dicQuery.Add("seed", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
@@ -83,31 +83,30 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
|
|
||||||
case nameof(ETransport.ws):
|
case nameof(ETransport.ws):
|
||||||
case nameof(ETransport.httpupgrade):
|
case nameof(ETransport.httpupgrade):
|
||||||
if (Utils.IsNotEmpty(item.RequestHost))
|
if (item.RequestHost.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Path))
|
if (item.Path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.splithttp):
|
|
||||||
case nameof(ETransport.xhttp):
|
case nameof(ETransport.xhttp):
|
||||||
if (Utils.IsNotEmpty(item.RequestHost))
|
if (item.RequestHost.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Path))
|
if (item.Path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.HeaderType) && Global.XhttpMode.Contains(item.HeaderType))
|
if (item.HeaderType.IsNotEmpty() && Global.XhttpMode.Contains(item.HeaderType))
|
||||||
{
|
{
|
||||||
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
|
dicQuery.Add("mode", Utils.UrlEncode(item.HeaderType));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Extra))
|
if (item.Extra.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
|
dicQuery.Add("extra", Utils.UrlEncode(item.Extra));
|
||||||
}
|
}
|
||||||
@@ -116,24 +115,24 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
case nameof(ETransport.http):
|
case nameof(ETransport.http):
|
||||||
case nameof(ETransport.h2):
|
case nameof(ETransport.h2):
|
||||||
dicQuery["type"] = nameof(ETransport.http);
|
dicQuery["type"] = nameof(ETransport.http);
|
||||||
if (Utils.IsNotEmpty(item.RequestHost))
|
if (item.RequestHost.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("host", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Path))
|
if (item.Path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
dicQuery.Add("path", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.quic):
|
case nameof(ETransport.quic):
|
||||||
dicQuery.Add("headerType", Utils.IsNotEmpty(item.HeaderType) ? item.HeaderType : Global.None);
|
dicQuery.Add("headerType", item.HeaderType.IsNotEmpty() ? item.HeaderType : Global.None);
|
||||||
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("quicSecurity", Utils.UrlEncode(item.RequestHost));
|
||||||
dicQuery.Add("key", Utils.UrlEncode(item.Path));
|
dicQuery.Add("key", Utils.UrlEncode(item.Path));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.grpc):
|
case nameof(ETransport.grpc):
|
||||||
if (Utils.IsNotEmpty(item.Path))
|
if (item.Path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("authority", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("authority", Utils.UrlEncode(item.RequestHost));
|
||||||
dicQuery.Add("serviceName", Utils.UrlEncode(item.Path));
|
dicQuery.Add("serviceName", Utils.UrlEncode(item.Path));
|
||||||
@@ -179,7 +178,6 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
item.Path = Utils.UrlDecode(query["path"] ?? "/");
|
item.Path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case nameof(ETransport.splithttp):
|
|
||||||
case nameof(ETransport.xhttp):
|
case nameof(ETransport.xhttp):
|
||||||
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
|
item.RequestHost = Utils.UrlDecode(query["host"] ?? "");
|
||||||
item.Path = Utils.UrlDecode(query["path"] ?? "/");
|
item.Path = Utils.UrlDecode(query["path"] ?? "/");
|
||||||
@@ -216,7 +214,10 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
foreach (var item in s)
|
foreach (var item in s)
|
||||||
{
|
{
|
||||||
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
|
if (str.Contains(item, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
{
|
{
|
||||||
public class FmtHandler
|
public class FmtHandler
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "FmtHandler";
|
||||||
|
|
||||||
public static string? GetShareUri(ProfileItem item)
|
public static string? GetShareUri(ProfileItem item)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -23,7 +25,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +37,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
string str = config.TrimEx();
|
string str = config.TrimEx();
|
||||||
if (Utils.IsNullOrEmpty(str))
|
if (str.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
msg = ResUI.FailedReadConfiguration;
|
msg = ResUI.FailedReadConfiguration;
|
||||||
return null;
|
return null;
|
||||||
@@ -81,7 +83,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
msg = ResUI.Incorrectconfiguration;
|
msg = ResUI.Incorrectconfiguration;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class Hysteria2Fmt : BaseFmt
|
public class Hysteria2Fmt : BaseFmt
|
||||||
{
|
{
|
||||||
@@ -11,7 +11,8 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
var url = Utils.TryUri(str);
|
var url = Utils.TryUri(str);
|
||||||
if (url == null) return null;
|
if (url == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
item.Address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.Port = url.Port;
|
item.Port = url.Port;
|
||||||
@@ -23,34 +24,41 @@
|
|||||||
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
|
||||||
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
|
||||||
|
|
||||||
|
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
|
return null;
|
||||||
string url = string.Empty;
|
string url = string.Empty;
|
||||||
|
|
||||||
string remark = string.Empty;
|
string remark = string.Empty;
|
||||||
if (Utils.IsNotEmpty(item.Remarks))
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (Utils.IsNotEmpty(item.Sni))
|
if (item.Sni.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("sni", item.Sni);
|
dicQuery.Add("sni", item.Sni);
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Alpn))
|
if (item.Alpn.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Path))
|
if (item.Path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("obfs", "salamander");
|
dicQuery.Add("obfs", "salamander");
|
||||||
dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
|
dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0");
|
dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0");
|
||||||
|
if (item.Ports.IsNotEmpty())
|
||||||
|
{
|
||||||
|
dicQuery.Add("mport", Utils.UrlEncode(item.Ports.Replace(':', '-')));
|
||||||
|
}
|
||||||
|
|
||||||
return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark);
|
return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
@@ -26,11 +26,12 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
string url = string.Empty;
|
{
|
||||||
|
return null;
|
||||||
string remark = string.Empty;
|
}
|
||||||
if (Utils.IsNotEmpty(item.Remarks))
|
var remark = string.Empty;
|
||||||
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
@@ -52,12 +53,14 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
var match = UrlFinder.Match(result);
|
var match = UrlFinder.Match(result);
|
||||||
if (!match.Success)
|
if (!match.Success)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ProfileItem item = new();
|
ProfileItem item = new();
|
||||||
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
var base64 = match.Groups["base64"].Value.TrimEnd('/');
|
||||||
var tag = match.Groups["tag"].Value;
|
var tag = match.Groups["tag"].Value;
|
||||||
if (Utils.IsNotEmpty(tag))
|
if (tag.IsNotEmpty())
|
||||||
{
|
{
|
||||||
item.Remarks = Utils.UrlDecode(tag);
|
item.Remarks = Utils.UrlDecode(tag);
|
||||||
}
|
}
|
||||||
@@ -71,18 +74,23 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!details.Success)
|
if (!details.Success)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
item.Security = details.Groups["method"].Value;
|
item.Security = details.Groups["method"].Value;
|
||||||
item.Id = details.Groups["password"].Value;
|
item.Id = details.Groups["password"].Value;
|
||||||
item.Address = details.Groups["hostname"].Value;
|
item.Address = details.Groups["hostname"].Value;
|
||||||
item.Port = Utils.ToInt(details.Groups["port"].Value);
|
item.Port = details.Groups["port"].Value.ToInt();
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ProfileItem? ResolveSip002(string result)
|
private static ProfileItem? ResolveSip002(string result)
|
||||||
{
|
{
|
||||||
var parsedUrl = Utils.TryUri(result);
|
var parsedUrl = Utils.TryUri(result);
|
||||||
if (parsedUrl == null) return null;
|
if (parsedUrl == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
@@ -94,25 +102,25 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
//2022-blake3
|
//2022-blake3
|
||||||
if (rawUserInfo.Contains(':'))
|
if (rawUserInfo.Contains(':'))
|
||||||
{
|
{
|
||||||
string[] userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||||
if (userInfoParts.Length != 2)
|
if (userInfoParts.Length != 2)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
item.Security = userInfoParts[0];
|
item.Security = userInfoParts.First();
|
||||||
item.Id = Utils.UrlDecode(userInfoParts[1]);
|
item.Id = Utils.UrlDecode(userInfoParts.Last());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// parse base64 UserInfo
|
// parse base64 UserInfo
|
||||||
string userInfo = Utils.Base64Decode(rawUserInfo);
|
var userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
string[] userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
||||||
if (userInfoParts.Length != 2)
|
if (userInfoParts.Length != 2)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
item.Security = userInfoParts[0];
|
item.Security = userInfoParts.First();
|
||||||
item.Id = userInfoParts[1];
|
item.Id = userInfoParts.Last();
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
var queryParameters = Utils.ParseQueryString(parsedUrl.Query);
|
||||||
@@ -120,7 +128,7 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
{
|
{
|
||||||
//obfs-host exists
|
//obfs-host exists
|
||||||
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
var obfsHost = queryParameters["plugin"]?.Split(';').FirstOrDefault(t => t.Contains("obfs-host"));
|
||||||
if (queryParameters["plugin"].Contains("obfs=http") && Utils.IsNotEmpty(obfsHost))
|
if (queryParameters["plugin"].Contains("obfs=http") && obfsHost.IsNotEmpty())
|
||||||
{
|
{
|
||||||
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
obfsHost = obfsHost?.Replace("obfs-host=", "");
|
||||||
item.Network = Global.DefaultNetwork;
|
item.Network = Global.DefaultNetwork;
|
||||||
@@ -160,7 +168,7 @@ namespace ServiceLib.Handler.Fmt
|
|||||||
Security = it.method,
|
Security = it.method,
|
||||||
Id = it.password,
|
Id = it.password,
|
||||||
Address = it.server,
|
Address = it.server,
|
||||||
Port = Utils.ToInt(it.server_port)
|
Port = it.server_port.ToInt()
|
||||||
};
|
};
|
||||||
lst.Add(ssItem);
|
lst.Add(ssItem);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class SingboxFmt : BaseFmt
|
public class SingboxFmt : BaseFmt
|
||||||
{
|
{
|
||||||
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||||
{
|
{
|
||||||
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
var configObjects = JsonUtils.Deserialize<object[]>(strData);
|
||||||
if (configObjects != null && configObjects.Length > 0)
|
if (configObjects != null && configObjects.Length > 0)
|
||||||
{
|
{
|
||||||
List<ProfileItem> lstResult = [];
|
List<ProfileItem> lstResult = [];
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class SocksFmt : BaseFmt
|
public class SocksFmt : BaseFmt
|
||||||
{
|
{
|
||||||
public static ProfileItem? Resolve(string str, out string msg)
|
public static ProfileItem? Resolve(string str, out string msg)
|
||||||
{
|
{
|
||||||
msg = ResUI.ConfigurationFormatIncorrect;
|
msg = ResUI.ConfigurationFormatIncorrect;
|
||||||
ProfileItem? item;
|
|
||||||
|
|
||||||
item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
var item = ResolveSocksNew(str) ?? ResolveSocks(str);
|
||||||
if (item == null)
|
if (item == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@@ -24,20 +23,15 @@
|
|||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
string url = string.Empty;
|
{
|
||||||
|
return null;
|
||||||
string remark = string.Empty;
|
}
|
||||||
if (Utils.IsNotEmpty(item.Remarks))
|
var remark = string.Empty;
|
||||||
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
//url = string.Format("{0}:{1}@{2}:{3}",
|
|
||||||
// item.security,
|
|
||||||
// item.id,
|
|
||||||
// item.address,
|
|
||||||
// item.port);
|
|
||||||
//url = Utile.Base64Encode(url);
|
|
||||||
//new
|
//new
|
||||||
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
|
var pw = Utils.Base64Encode($"{item.Security}:{item.Id}");
|
||||||
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
|
return ToUri(EConfigType.SOCKS, item.Address, item.Port, pw, null, remark);
|
||||||
@@ -51,7 +45,7 @@
|
|||||||
};
|
};
|
||||||
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
|
result = result[Global.ProtocolShares[EConfigType.SOCKS].Length..];
|
||||||
//remark
|
//remark
|
||||||
int indexRemark = result.IndexOf("#");
|
var indexRemark = result.IndexOf("#");
|
||||||
if (indexRemark > 0)
|
if (indexRemark > 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -62,7 +56,7 @@
|
|||||||
result = result[..indexRemark];
|
result = result[..indexRemark];
|
||||||
}
|
}
|
||||||
//part decode
|
//part decode
|
||||||
int indexS = result.IndexOf("@");
|
var indexS = result.IndexOf("@");
|
||||||
if (indexS > 0)
|
if (indexS > 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -71,21 +65,20 @@
|
|||||||
result = Utils.Base64Decode(result);
|
result = Utils.Base64Decode(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] arr1 = result.Split('@');
|
var arr1 = result.Split('@');
|
||||||
if (arr1.Length != 2)
|
if (arr1.Length != 2)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
string[] arr21 = arr1[0].Split(':');
|
var arr21 = arr1.First().Split(':');
|
||||||
//string[] arr22 = arr1[1].Split(':');
|
var indexPort = arr1.Last().LastIndexOf(":");
|
||||||
int indexPort = arr1[1].LastIndexOf(":");
|
|
||||||
if (arr21.Length != 2 || indexPort < 0)
|
if (arr21.Length != 2 || indexPort < 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
item.Address = arr1[1][..indexPort];
|
item.Address = arr1[1][..indexPort];
|
||||||
item.Port = Utils.ToInt(arr1[1][(indexPort + 1)..]);
|
item.Port = arr1[1][(indexPort + 1)..].ToInt();
|
||||||
item.Security = arr21[0];
|
item.Security = arr21.First();
|
||||||
item.Id = arr21[1];
|
item.Id = arr21[1];
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@@ -94,7 +87,10 @@
|
|||||||
private static ProfileItem? ResolveSocksNew(string result)
|
private static ProfileItem? ResolveSocksNew(string result)
|
||||||
{
|
{
|
||||||
var parsedUrl = Utils.TryUri(result);
|
var parsedUrl = Utils.TryUri(result);
|
||||||
if (parsedUrl == null) return null;
|
if (parsedUrl == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
ProfileItem item = new()
|
ProfileItem item = new()
|
||||||
{
|
{
|
||||||
@@ -106,10 +102,10 @@
|
|||||||
// parse base64 UserInfo
|
// parse base64 UserInfo
|
||||||
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
var rawUserInfo = Utils.UrlDecode(parsedUrl.UserInfo);
|
||||||
var userInfo = Utils.Base64Decode(rawUserInfo);
|
var userInfo = Utils.Base64Decode(rawUserInfo);
|
||||||
var userInfoParts = userInfo.Split(new[] { ':' }, 2);
|
var userInfoParts = userInfo.Split([':'], 2);
|
||||||
if (userInfoParts.Length == 2)
|
if (userInfoParts.Length == 2)
|
||||||
{
|
{
|
||||||
item.Security = userInfoParts[0];
|
item.Security = userInfoParts.First();
|
||||||
item.Id = userInfoParts[1];
|
item.Id = userInfoParts[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class TrojanFmt : BaseFmt
|
public class TrojanFmt : BaseFmt
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
var url = Utils.TryUri(str);
|
var url = Utils.TryUri(str);
|
||||||
if (url == null) return null;
|
if (url == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
item.Address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.Port = url.Port;
|
item.Port = url.Port;
|
||||||
@@ -20,23 +23,24 @@
|
|||||||
item.Id = Utils.UrlDecode(url.UserInfo);
|
item.Id = Utils.UrlDecode(url.UserInfo);
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
ResolveStdTransport(query, ref item);
|
_ = ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
string url = string.Empty;
|
{
|
||||||
|
return null;
|
||||||
string remark = string.Empty;
|
}
|
||||||
if (Utils.IsNotEmpty(item.Remarks))
|
var remark = string.Empty;
|
||||||
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
GetStdTransport(item, null, ref dicQuery);
|
_ = GetStdTransport(item, null, ref dicQuery);
|
||||||
|
|
||||||
return ToUri(EConfigType.Trojan, item.Address, item.Port, item.Id, dicQuery, remark);
|
return ToUri(EConfigType.Trojan, item.Address, item.Port, item.Id, dicQuery, remark);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class TuicFmt : BaseFmt
|
public class TuicFmt : BaseFmt
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
var url = Utils.TryUri(str);
|
var url = Utils.TryUri(str);
|
||||||
if (url == null) return null;
|
if (url == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
item.Address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.Port = url.Port;
|
item.Port = url.Port;
|
||||||
@@ -21,8 +24,8 @@
|
|||||||
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
var userInfoParts = rawUserInfo.Split(new[] { ':' }, 2);
|
||||||
if (userInfoParts.Length == 2)
|
if (userInfoParts.Length == 2)
|
||||||
{
|
{
|
||||||
item.Id = userInfoParts[0];
|
item.Id = userInfoParts.First();
|
||||||
item.Security = userInfoParts[1];
|
item.Security = userInfoParts.Last();
|
||||||
}
|
}
|
||||||
|
|
||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
@@ -34,20 +37,22 @@
|
|||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
string url = string.Empty;
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
string remark = string.Empty;
|
var remark = string.Empty;
|
||||||
if (Utils.IsNotEmpty(item.Remarks))
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (Utils.IsNotEmpty(item.Sni))
|
if (item.Sni.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("sni", item.Sni);
|
dicQuery.Add("sni", item.Sni);
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Alpn))
|
if (item.Alpn.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
dicQuery.Add("alpn", Utils.UrlEncode(item.Alpn));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class V2rayFmt : BaseFmt
|
public class V2rayFmt : BaseFmt
|
||||||
{
|
{
|
||||||
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
public static List<ProfileItem>? ResolveFullArray(string strData, string? subRemarks)
|
||||||
{
|
{
|
||||||
var configObjects = JsonUtils.Deserialize<Object[]>(strData);
|
var configObjects = JsonUtils.Deserialize<object[]>(strData);
|
||||||
if (configObjects != null && configObjects.Length > 0)
|
if (configObjects != null && configObjects.Length > 0)
|
||||||
{
|
{
|
||||||
List<ProfileItem> lstResult = [];
|
List<ProfileItem> lstResult = [];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class VLESSFmt : BaseFmt
|
public class VLESSFmt : BaseFmt
|
||||||
{
|
{
|
||||||
@@ -13,7 +13,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
var url = Utils.TryUri(str);
|
var url = Utils.TryUri(str);
|
||||||
if (url == null) return null;
|
if (url == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
item.Address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.Port = url.Port;
|
item.Port = url.Port;
|
||||||
@@ -23,23 +26,25 @@
|
|||||||
var query = Utils.ParseQueryString(url.Query);
|
var query = Utils.ParseQueryString(url.Query);
|
||||||
item.Security = query["encryption"] ?? Global.None;
|
item.Security = query["encryption"] ?? Global.None;
|
||||||
item.StreamSecurity = query["security"] ?? "";
|
item.StreamSecurity = query["security"] ?? "";
|
||||||
ResolveStdTransport(query, ref item);
|
_ = ResolveStdTransport(query, ref item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
string url = string.Empty;
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
string remark = string.Empty;
|
var remark = string.Empty;
|
||||||
if (Utils.IsNotEmpty(item.Remarks))
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (Utils.IsNotEmpty(item.Security))
|
if (item.Security.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("encryption", item.Security);
|
dicQuery.Add("encryption", item.Security);
|
||||||
}
|
}
|
||||||
@@ -47,7 +52,7 @@
|
|||||||
{
|
{
|
||||||
dicQuery.Add("encryption", Global.None);
|
dicQuery.Add("encryption", Global.None);
|
||||||
}
|
}
|
||||||
GetStdTransport(item, Global.None, ref dicQuery);
|
_ = GetStdTransport(item, Global.None, ref dicQuery);
|
||||||
|
|
||||||
return ToUri(EConfigType.VLESS, item.Address, item.Port, item.Id, dicQuery, remark);
|
return ToUri(EConfigType.VLESS, item.Address, item.Port, item.Id, dicQuery, remark);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class VmessFmt : BaseFmt
|
public class VmessFmt : BaseFmt
|
||||||
{
|
{
|
||||||
@@ -19,10 +19,11 @@
|
|||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
string url = string.Empty;
|
{
|
||||||
|
return null;
|
||||||
VmessQRCode vmessQRCode = new()
|
}
|
||||||
|
var vmessQRCode = new VmessQRCode
|
||||||
{
|
{
|
||||||
v = item.ConfigVersion,
|
v = item.ConfigVersion,
|
||||||
ps = item.Remarks.TrimEx(),
|
ps = item.Remarks.TrimEx(),
|
||||||
@@ -41,7 +42,7 @@
|
|||||||
fp = item.Fingerprint
|
fp = item.Fingerprint
|
||||||
};
|
};
|
||||||
|
|
||||||
url = JsonUtils.Serialize(vmessQRCode);
|
var url = JsonUtils.Serialize(vmessQRCode);
|
||||||
url = Utils.Base64Encode(url);
|
url = Utils.Base64Encode(url);
|
||||||
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
|
url = $"{Global.ProtocolShares[EConfigType.VMess]}{url}";
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
result = result[Global.ProtocolShares[EConfigType.VMess].Length..];
|
||||||
result = Utils.Base64Decode(result);
|
result = Utils.Base64Decode(result);
|
||||||
|
|
||||||
VmessQRCode? vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
var vmessQRCode = JsonUtils.Deserialize<VmessQRCode>(result);
|
||||||
if (vmessQRCode == null)
|
if (vmessQRCode == null)
|
||||||
{
|
{
|
||||||
msg = ResUI.FailedConversionConfiguration;
|
msg = ResUI.FailedConversionConfiguration;
|
||||||
@@ -77,12 +78,12 @@
|
|||||||
item.AlterId = vmessQRCode.aid;
|
item.AlterId = vmessQRCode.aid;
|
||||||
item.Security = Utils.ToString(vmessQRCode.scy);
|
item.Security = Utils.ToString(vmessQRCode.scy);
|
||||||
|
|
||||||
item.Security = Utils.IsNotEmpty(vmessQRCode.scy) ? vmessQRCode.scy : Global.DefaultSecurity;
|
item.Security = vmessQRCode.scy.IsNotEmpty() ? vmessQRCode.scy : Global.DefaultSecurity;
|
||||||
if (Utils.IsNotEmpty(vmessQRCode.net))
|
if (vmessQRCode.net.IsNotEmpty())
|
||||||
{
|
{
|
||||||
item.Network = vmessQRCode.net;
|
item.Network = vmessQRCode.net;
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(vmessQRCode.type))
|
if (vmessQRCode.type.IsNotEmpty())
|
||||||
{
|
{
|
||||||
item.HeaderType = vmessQRCode.type;
|
item.HeaderType = vmessQRCode.type;
|
||||||
}
|
}
|
||||||
@@ -99,14 +100,17 @@
|
|||||||
|
|
||||||
public static ProfileItem? ResolveStdVmess(string str)
|
public static ProfileItem? ResolveStdVmess(string str)
|
||||||
{
|
{
|
||||||
ProfileItem item = new()
|
var item = new ProfileItem
|
||||||
{
|
{
|
||||||
ConfigType = EConfigType.VMess,
|
ConfigType = EConfigType.VMess,
|
||||||
Security = "auto"
|
Security = "auto"
|
||||||
};
|
};
|
||||||
|
|
||||||
var url = Utils.TryUri(str);
|
var url = Utils.TryUri(str);
|
||||||
if (url == null) return null;
|
if (url == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
item.Address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.Port = url.Port;
|
item.Port = url.Port;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler.Fmt
|
namespace ServiceLib.Handler.Fmt
|
||||||
{
|
{
|
||||||
public class WireguardFmt : BaseFmt
|
public class WireguardFmt : BaseFmt
|
||||||
{
|
{
|
||||||
@@ -12,7 +12,10 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
var url = Utils.TryUri(str);
|
var url = Utils.TryUri(str);
|
||||||
if (url == null) return null;
|
if (url == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
item.Address = url.IdnHost;
|
item.Address = url.IdnHost;
|
||||||
item.Port = url.Port;
|
item.Port = url.Port;
|
||||||
@@ -31,29 +34,31 @@
|
|||||||
|
|
||||||
public static string? ToUri(ProfileItem? item)
|
public static string? ToUri(ProfileItem? item)
|
||||||
{
|
{
|
||||||
if (item == null) return null;
|
if (item == null)
|
||||||
string url = string.Empty;
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
string remark = string.Empty;
|
var remark = string.Empty;
|
||||||
if (Utils.IsNotEmpty(item.Remarks))
|
if (item.Remarks.IsNotEmpty())
|
||||||
{
|
{
|
||||||
remark = "#" + Utils.UrlEncode(item.Remarks);
|
remark = "#" + Utils.UrlEncode(item.Remarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dicQuery = new Dictionary<string, string>();
|
var dicQuery = new Dictionary<string, string>();
|
||||||
if (Utils.IsNotEmpty(item.PublicKey))
|
if (item.PublicKey.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("publickey", Utils.UrlEncode(item.PublicKey));
|
dicQuery.Add("publickey", Utils.UrlEncode(item.PublicKey));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.Path))
|
if (item.Path.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("reserved", Utils.UrlEncode(item.Path));
|
dicQuery.Add("reserved", Utils.UrlEncode(item.Path));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.RequestHost))
|
if (item.RequestHost.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("address", Utils.UrlEncode(item.RequestHost));
|
dicQuery.Add("address", Utils.UrlEncode(item.RequestHost));
|
||||||
}
|
}
|
||||||
if (Utils.IsNotEmpty(item.ShortId))
|
if (item.ShortId.IsNotEmpty())
|
||||||
{
|
{
|
||||||
dicQuery.Add("mtu", Utils.UrlEncode(item.ShortId));
|
dicQuery.Add("mtu", Utils.UrlEncode(item.ShortId));
|
||||||
}
|
}
|
||||||
|
|||||||
108
v2rayN/ServiceLib/Handler/PacHandler.cs
Normal file
108
v2rayN/ServiceLib/Handler/PacHandler.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ServiceLib.Handler
|
||||||
|
{
|
||||||
|
public class PacHandler
|
||||||
|
{
|
||||||
|
private static string _configPath;
|
||||||
|
private static int _httpPort;
|
||||||
|
private static int _pacPort;
|
||||||
|
private static TcpListener? _tcpListener;
|
||||||
|
private static byte[] _writeContent;
|
||||||
|
private static bool _isRunning;
|
||||||
|
private static bool _needRestart = true;
|
||||||
|
|
||||||
|
public static async Task Start(string configPath, int httpPort, int pacPort)
|
||||||
|
{
|
||||||
|
_needRestart = configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning;
|
||||||
|
|
||||||
|
_configPath = configPath;
|
||||||
|
_httpPort = httpPort;
|
||||||
|
_pacPort = pacPort;
|
||||||
|
|
||||||
|
await InitText();
|
||||||
|
|
||||||
|
if (_needRestart)
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
RunListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task InitText()
|
||||||
|
{
|
||||||
|
var path = Path.Combine(_configPath, "pac.txt");
|
||||||
|
if (!File.Exists(path))
|
||||||
|
{
|
||||||
|
var pac = EmbedUtils.GetEmbedText(Global.PacFileName);
|
||||||
|
await File.AppendAllTextAsync(path, pac);
|
||||||
|
}
|
||||||
|
|
||||||
|
var pacText =
|
||||||
|
(await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine("HTTP/1.0 200 OK");
|
||||||
|
sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
|
||||||
|
sb.AppendLine("Connection:close");
|
||||||
|
sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
|
||||||
|
sb.AppendLine();
|
||||||
|
sb.Append(pacText);
|
||||||
|
_writeContent = Encoding.UTF8.GetBytes(sb.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RunListener()
|
||||||
|
{
|
||||||
|
_tcpListener = TcpListener.Create(_pacPort);
|
||||||
|
_isRunning = true;
|
||||||
|
_tcpListener.Start();
|
||||||
|
Task.Factory.StartNew(async () =>
|
||||||
|
{
|
||||||
|
while (_isRunning)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_tcpListener.Pending())
|
||||||
|
{
|
||||||
|
await Task.Delay(10);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var client = await _tcpListener.AcceptTcpClientAsync();
|
||||||
|
await Task.Run(() => WriteContent(client));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, TaskCreationOptions.LongRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void WriteContent(TcpClient client)
|
||||||
|
{
|
||||||
|
var stream = client.GetStream();
|
||||||
|
stream.Write(_writeContent, 0, _writeContent.Length);
|
||||||
|
stream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stop()
|
||||||
|
{
|
||||||
|
if (_tcpListener == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_isRunning = false;
|
||||||
|
_tcpListener.Stop();
|
||||||
|
_tcpListener = null;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
//using System.Reactive.Linq;
|
//using System.Reactive.Linq;
|
||||||
|
|
||||||
@@ -8,8 +8,9 @@ namespace ServiceLib.Handler
|
|||||||
{
|
{
|
||||||
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
private static readonly Lazy<ProfileExHandler> _instance = new(() => new());
|
||||||
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
private ConcurrentBag<ProfileExItem> _lstProfileEx = [];
|
||||||
private Queue<string> _queIndexIds = new();
|
private readonly Queue<string> _queIndexIds = new();
|
||||||
public static ProfileExHandler Instance => _instance.Value;
|
public static ProfileExHandler Instance => _instance.Value;
|
||||||
|
private static readonly string _tag = "ProfileExHandler";
|
||||||
|
|
||||||
public ProfileExHandler()
|
public ProfileExHandler()
|
||||||
{
|
{
|
||||||
@@ -19,19 +20,11 @@ namespace ServiceLib.Handler
|
|||||||
public async Task Init()
|
public async Task Init()
|
||||||
{
|
{
|
||||||
await InitData();
|
await InitData();
|
||||||
Task.Run(async () =>
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
await Task.Delay(1000 * 600);
|
|
||||||
await SaveQueueIndexIds();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()
|
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()
|
||||||
{
|
{
|
||||||
return _lstProfileEx;
|
return await Task.FromResult(_lstProfileEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InitData()
|
private async Task InitData()
|
||||||
@@ -43,7 +36,7 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private void IndexIdEnqueue(string indexId)
|
private void IndexIdEnqueue(string indexId)
|
||||||
{
|
{
|
||||||
if (Utils.IsNotEmpty(indexId) && !_queIndexIds.Contains(indexId))
|
if (indexId.IsNotEmpty() && !_queIndexIds.Contains(indexId))
|
||||||
{
|
{
|
||||||
_queIndexIds.Enqueue(indexId);
|
_queIndexIds.Enqueue(indexId);
|
||||||
}
|
}
|
||||||
@@ -58,7 +51,7 @@ namespace ServiceLib.Handler
|
|||||||
List<ProfileExItem> lstInserts = [];
|
List<ProfileExItem> lstInserts = [];
|
||||||
List<ProfileExItem> lstUpdates = [];
|
List<ProfileExItem> lstUpdates = [];
|
||||||
|
|
||||||
for (int i = 0; i < cnt; i++)
|
for (var i = 0; i < cnt; i++)
|
||||||
{
|
{
|
||||||
var id = _queIndexIds.Dequeue();
|
var id = _queIndexIds.Dequeue();
|
||||||
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
|
var item = lstExists.FirstOrDefault(t => t.IndexId == id);
|
||||||
@@ -77,32 +70,44 @@ namespace ServiceLib.Handler
|
|||||||
lstInserts.Add(itemNew);
|
lstInserts.Add(itemNew);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (lstInserts.Count() > 0)
|
if (lstInserts.Count > 0)
|
||||||
|
{
|
||||||
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
|
await SQLiteHelper.Instance.InsertAllAsync(lstInserts);
|
||||||
|
}
|
||||||
|
|
||||||
if (lstUpdates.Count() > 0)
|
if (lstUpdates.Count > 0)
|
||||||
|
{
|
||||||
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
|
await SQLiteHelper.Instance.UpdateAllAsync(lstUpdates);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog("ProfileExHandler", ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddProfileEx(string indexId, ref ProfileExItem? profileEx)
|
private ProfileExItem AddProfileEx(string indexId)
|
||||||
{
|
{
|
||||||
profileEx = new()
|
var profileEx = new ProfileExItem()
|
||||||
{
|
{
|
||||||
IndexId = indexId,
|
IndexId = indexId,
|
||||||
Delay = 0,
|
Delay = 0,
|
||||||
Speed = 0,
|
Speed = 0,
|
||||||
Sort = 0
|
Sort = 0,
|
||||||
|
Message = string.Empty
|
||||||
};
|
};
|
||||||
_lstProfileEx.Add(profileEx);
|
_lstProfileEx.Add(profileEx);
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
|
return profileEx;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProfileExItem GetProfileExItem(string? indexId)
|
||||||
|
{
|
||||||
|
return _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId) ?? AddProfileEx(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task ClearAll()
|
public async Task ClearAll()
|
||||||
@@ -119,43 +124,38 @@ namespace ServiceLib.Handler
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTestDelay(string indexId, string delayVal)
|
public void SetTestDelay(string indexId, int delay)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
var profileEx = GetProfileExItem(indexId);
|
||||||
if (profileEx == null)
|
|
||||||
{
|
|
||||||
AddProfileEx(indexId, ref profileEx);
|
|
||||||
}
|
|
||||||
|
|
||||||
int.TryParse(delayVal, out int delay);
|
|
||||||
profileEx.Delay = delay;
|
profileEx.Delay = delay;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTestSpeed(string indexId, string speedVal)
|
public void SetTestSpeed(string indexId, decimal speed)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
var profileEx = GetProfileExItem(indexId);
|
||||||
if (profileEx == null)
|
|
||||||
{
|
profileEx.Speed = speed;
|
||||||
AddProfileEx(indexId, ref profileEx);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
decimal.TryParse(speedVal, out decimal speed);
|
public void SetTestMessage(string indexId, string message)
|
||||||
profileEx.Speed = speed;
|
{
|
||||||
|
var profileEx = GetProfileExItem(indexId);
|
||||||
|
|
||||||
|
profileEx.Message = message;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSort(string indexId, int sort)
|
public void SetSort(string indexId, int sort)
|
||||||
{
|
{
|
||||||
var profileEx = _lstProfileEx.FirstOrDefault(t => t.IndexId == indexId);
|
var profileEx = GetProfileExItem(indexId);
|
||||||
if (profileEx == null)
|
|
||||||
{
|
|
||||||
AddProfileEx(indexId, ref profileEx);
|
|
||||||
}
|
|
||||||
profileEx.Sort = sort;
|
profileEx.Sort = sort;
|
||||||
IndexIdEnqueue(indexId);
|
IndexIdEnqueue(indexId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,23 +12,21 @@
|
|||||||
|
|
||||||
private StatisticsXrayService? _statisticsXray;
|
private StatisticsXrayService? _statisticsXray;
|
||||||
private StatisticsSingboxService? _statisticsSingbox;
|
private StatisticsSingboxService? _statisticsSingbox;
|
||||||
|
private static readonly string _tag = "StatisticsHandler";
|
||||||
public List<ServerStatItem> ServerStat => _lstServerStat;
|
public List<ServerStatItem> ServerStat => _lstServerStat;
|
||||||
|
|
||||||
public async Task Init(Config config, Action<ServerSpeedItem> updateFunc)
|
public async Task Init(Config config, Action<ServerSpeedItem> updateFunc)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
_updateFunc = updateFunc;
|
_updateFunc = updateFunc;
|
||||||
if (!config.GuiItem.EnableStatistics)
|
if (config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await InitData();
|
await InitData();
|
||||||
|
|
||||||
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
_statisticsXray = new StatisticsXrayService(config, UpdateServerStatHandler);
|
||||||
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
|
_statisticsSingbox = new StatisticsSingboxService(config, UpdateServerStatHandler);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Close()
|
public void Close()
|
||||||
{
|
{
|
||||||
@@ -39,7 +37,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +59,7 @@
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +70,11 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (indexId == toIndexId)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
|
var stat = _lstServerStat.FirstOrDefault(t => t.IndexId == indexId);
|
||||||
if (stat == null)
|
if (stat == null)
|
||||||
{
|
{
|
||||||
@@ -96,7 +99,7 @@
|
|||||||
|
|
||||||
private void UpdateServerStatHandler(ServerSpeedItem server)
|
private void UpdateServerStatHandler(ServerSpeedItem server)
|
||||||
{
|
{
|
||||||
UpdateServerStat(server);
|
_ = UpdateServerStat(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateServerStat(ServerSpeedItem server)
|
private async Task UpdateServerStat(ServerSpeedItem server)
|
||||||
|
|||||||
@@ -1,152 +1,33 @@
|
|||||||
namespace ServiceLib.Handler.SysProxy
|
namespace ServiceLib.Handler.SysProxy
|
||||||
{
|
{
|
||||||
public class ProxySettingLinux
|
public class ProxySettingLinux
|
||||||
{
|
{
|
||||||
public static async Task SetProxy(string host, int port)
|
private static readonly string _proxySetFileName = $"{Global.ProxySetLinuxShellFileName.Replace(Global.NamespaceSample, "")}.sh";
|
||||||
{
|
|
||||||
var lstCmd = GetSetCmds(host, port);
|
|
||||||
|
|
||||||
await ExecCmd(lstCmd);
|
public static async Task SetProxy(string host, int port, string exceptions)
|
||||||
|
{
|
||||||
|
List<string> args = ["manual", host, port.ToString(), exceptions];
|
||||||
|
await ExecCmd(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task UnsetProxy()
|
public static async Task UnsetProxy()
|
||||||
{
|
{
|
||||||
var lstCmd = GetUnsetCmds();
|
List<string> args = ["none"];
|
||||||
|
await ExecCmd(args);
|
||||||
await ExecCmd(lstCmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
private static async Task ExecCmd(List<string> args)
|
||||||
{
|
{
|
||||||
foreach (var cmd in lstCmd)
|
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
||||||
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
|
||||||
{
|
await File.AppendAllTextAsync(fileName, contents);
|
||||||
continue;
|
|
||||||
}
|
await Utils.SetLinuxChmod(fileName);
|
||||||
await Task.Delay(10);
|
|
||||||
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmds(string host, int port)
|
await Utils.GetCliWrapOutput(fileName, args);
|
||||||
{
|
|
||||||
var isKde = IsKde(out var configDir);
|
|
||||||
List<string> lstType = ["", "http", "https", "socks", "ftp"];
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
|
|
||||||
if (isKde)
|
|
||||||
{
|
|
||||||
foreach (var type in lstType)
|
|
||||||
{
|
|
||||||
lstCmd.AddRange(GetSetCmd4Kde(type, host, port, configDir));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var type in lstType)
|
|
||||||
{
|
|
||||||
lstCmd.AddRange(GetSetCmd4Gnome(type, host, port));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetUnsetCmds()
|
|
||||||
{
|
|
||||||
var isKde = IsKde(out var configDir);
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
|
|
||||||
if (isKde)
|
|
||||||
{
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "kwriteconfig5",
|
|
||||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "0"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "none"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmd4Kde(string type, string host, int port, string configDir)
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
|
|
||||||
if (type.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "kwriteconfig5",
|
|
||||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", "ProxyType", "1"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var type2 = type.Equals("https") ? "http" : type;
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "kwriteconfig5",
|
|
||||||
Arguments = ["--file", $"{configDir}/kioslaverc", "--group", "Proxy Settings", "--key", $"{type}Proxy", $"{type2}://{host}:{port}"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmd4Gnome(string type, string host, int port)
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
|
|
||||||
if (type.IsNullOrEmpty())
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", "org.gnome.system.proxy", "mode", "manual"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", $"org.gnome.system.proxy.{type}", "host", host]
|
|
||||||
});
|
|
||||||
|
|
||||||
lstCmd.Add(new()
|
|
||||||
{
|
|
||||||
Cmd = "gsettings",
|
|
||||||
Arguments = ["set", $"org.gnome.system.proxy.{type}", "port", $"{port}"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsKde(out string configDir)
|
|
||||||
{
|
|
||||||
configDir = "/home";
|
|
||||||
var desktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
|
|
||||||
var isKde = string.Equals(desktop, "KDE", StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (isKde)
|
|
||||||
{
|
|
||||||
var homeDir = Environment.GetEnvironmentVariable("HOME");
|
|
||||||
if (homeDir != null)
|
|
||||||
{
|
|
||||||
configDir = Path.Combine(homeDir, ".config");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return isKde;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,81 +1,38 @@
|
|||||||
namespace ServiceLib.Handler.SysProxy
|
namespace ServiceLib.Handler.SysProxy
|
||||||
{
|
{
|
||||||
public class ProxySettingOSX
|
public class ProxySettingOSX
|
||||||
{
|
{
|
||||||
/*
|
private static readonly string _proxySetFileName = $"{Global.ProxySetOSXShellFileName.Replace(Global.NamespaceSample, "")}.sh";
|
||||||
* 仅测试了,MacOS 13.7.1 x86 版本,其他版本有待确认
|
|
||||||
*/
|
|
||||||
|
|
||||||
/// <summary>
|
public static async Task SetProxy(string host, int port, string exceptions)
|
||||||
/// 应用接口类型
|
|
||||||
/// </summary>
|
|
||||||
private static readonly List<string> LstInterface = ["Ethernet", "Wi-Fi", "Thunderbolt Bridge"];
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 代理类型,对应 http,https,socks
|
|
||||||
/// </summary>
|
|
||||||
private static readonly List<string> LstTypes = ["setwebproxy", "setsecurewebproxy", "setsocksfirewallproxy"];
|
|
||||||
|
|
||||||
public static async Task SetProxy(string host, int port)
|
|
||||||
{
|
{
|
||||||
var lstCmd = GetSetCmds(host, port);
|
List<string> args = ["set", host, port.ToString()];
|
||||||
await ExecCmd(lstCmd);
|
if (exceptions.IsNotEmpty())
|
||||||
|
{
|
||||||
|
args.AddRange(exceptions.Split(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
await ExecCmd(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task UnsetProxy()
|
public static async Task UnsetProxy()
|
||||||
{
|
{
|
||||||
var lstCmd = GetUnsetCmds();
|
List<string> args = ["clear"];
|
||||||
await ExecCmd(lstCmd);
|
await ExecCmd(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task ExecCmd(List<CmdItem> lstCmd)
|
private static async Task ExecCmd(List<string> args)
|
||||||
{
|
{
|
||||||
foreach (var cmd in lstCmd)
|
var fileName = Utils.GetBinConfigPath(_proxySetFileName);
|
||||||
|
if (!File.Exists(fileName))
|
||||||
{
|
{
|
||||||
if (cmd is null || cmd.Cmd.IsNullOrEmpty() || cmd.Arguments is null)
|
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
|
||||||
{
|
await File.AppendAllTextAsync(fileName, contents);
|
||||||
continue;
|
|
||||||
|
await Utils.SetLinuxChmod(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(10);
|
await Utils.GetCliWrapOutput(fileName, args);
|
||||||
await Utils.GetCliWrapOutput(cmd.Cmd, cmd.Arguments);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetSetCmds(string host, int port)
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
foreach (var interf in LstInterface)
|
|
||||||
{
|
|
||||||
foreach (var type in LstTypes)
|
|
||||||
{
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "networksetup",
|
|
||||||
Arguments = [$"-{type}", interf, host, (type.Contains("socks") ? (port - 1) : port).ToString()]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<CmdItem> GetUnsetCmds()
|
|
||||||
{
|
|
||||||
List<CmdItem> lstCmd = [];
|
|
||||||
foreach (var interf in LstInterface)
|
|
||||||
{
|
|
||||||
foreach (var type in LstTypes)
|
|
||||||
{
|
|
||||||
lstCmd.Add(new CmdItem()
|
|
||||||
{
|
|
||||||
Cmd = "networksetup",
|
|
||||||
Arguments = [$"-{type}state", interf, "off"]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return lstCmd;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// set proxy for LAN
|
// set proxy for LAN
|
||||||
bool result = SetConnectionProxy(null, strProxy, exceptions, type);
|
var result = SetConnectionProxy(null, strProxy, exceptions, type);
|
||||||
// set proxy for dial up connections
|
// set proxy for dial up connections
|
||||||
var connections = EnumerateRasEntries();
|
var connections = EnumerateRasEntries();
|
||||||
foreach (var connection in connections)
|
foreach (var connection in connections)
|
||||||
@@ -69,30 +69,29 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch
|
||||||
{
|
{
|
||||||
SetProxyFallback(strProxy, exceptions, type);
|
_ = SetProxyFallback(strProxy, exceptions, type);
|
||||||
//Logging.SaveLog(ex.Message, ex);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
private static bool SetConnectionProxy(string? connectionName, string? strProxy, string? exceptions, int type)
|
||||||
{
|
{
|
||||||
InternetPerConnOptionList list = new();
|
var list = new InternetPerConnOptionList();
|
||||||
|
|
||||||
int optionCount = 1;
|
var optionCount = 1;
|
||||||
if (type == 1) // No proxy
|
if (type == 1) // No proxy
|
||||||
{
|
{
|
||||||
optionCount = 1;
|
optionCount = 1;
|
||||||
}
|
}
|
||||||
else if (type is 2 or 4) // named proxy or autoproxy script URL
|
else if (type is 2 or 4) // named proxy or autoproxy script URL
|
||||||
{
|
{
|
||||||
optionCount = string.IsNullOrEmpty(exceptions) ? 2 : 3;
|
optionCount = exceptions.IsNullOrEmpty() ? 2 : 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
|
var m_Int = (int)PerConnFlags.PROXY_TYPE_DIRECT;
|
||||||
PerConnOption m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
var m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
||||||
if (type == 2) // named proxy
|
if (type == 2) // named proxy
|
||||||
{
|
{
|
||||||
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
|
m_Int = (int)(PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY);
|
||||||
@@ -104,11 +103,9 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
|
m_Option = PerConnOption.INTERNET_PER_CONN_AUTOCONFIG_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//int optionCount = Utile.IsNullOrEmpty(strProxy) ? 1 : (Utile.IsNullOrEmpty(exceptions) ? 2 : 3);
|
var options = new InternetConnectionOption[optionCount];
|
||||||
InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
|
|
||||||
// USE a proxy server ...
|
// USE a proxy server ...
|
||||||
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
|
||||||
//options[0].m_Value.m_Int = (int)((optionCount < 2) ? PerConnFlags.PROXY_TYPE_DIRECT : (PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY));
|
|
||||||
options[0].m_Value.m_Int = m_Int;
|
options[0].m_Value.m_Int = m_Int;
|
||||||
// use THIS proxy server
|
// use THIS proxy server
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
@@ -136,20 +133,20 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
list.dwOptionCount = options.Length;
|
list.dwOptionCount = options.Length;
|
||||||
list.dwOptionError = 0;
|
list.dwOptionError = 0;
|
||||||
|
|
||||||
int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
var optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
|
||||||
// make a pointer out of all that ...
|
// make a pointer out of all that ...
|
||||||
nint optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
var optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length); // !! remember to deallocate memory 4
|
||||||
// copy the array over into that spot in memory ...
|
// copy the array over into that spot in memory ...
|
||||||
for (int i = 0; i < options.Length; ++i)
|
for (var i = 0; i < options.Length; ++i)
|
||||||
{
|
{
|
||||||
if (Environment.Is64BitOperatingSystem)
|
if (Environment.Is64BitOperatingSystem)
|
||||||
{
|
{
|
||||||
nint opt = new(optionsPtr.ToInt64() + (i * optSize));
|
var opt = new nint(optionsPtr.ToInt64() + (i * optSize));
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nint opt = new(optionsPtr.ToInt32() + (i * optSize));
|
var opt = new nint(optionsPtr.ToInt32() + (i * optSize));
|
||||||
Marshal.StructureToPtr(options[i], opt, false);
|
Marshal.StructureToPtr(options[i], opt, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -157,14 +154,14 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
list.options = optionsPtr;
|
list.options = optionsPtr;
|
||||||
|
|
||||||
// and then make a pointer out of the whole list
|
// and then make a pointer out of the whole list
|
||||||
nint ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
var ipcoListPtr = Marshal.AllocCoTaskMem(list.dwSize); // !! remember to deallocate memory 5
|
||||||
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
Marshal.StructureToPtr(list, ipcoListPtr, false);
|
||||||
|
|
||||||
// and finally, call the API method!
|
// and finally, call the API method!
|
||||||
bool isSuccess = NativeMethods.InternetSetOption(nint.Zero,
|
var isSuccess = NativeMethods.InternetSetOption(nint.Zero,
|
||||||
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
|
||||||
ipcoListPtr, list.dwSize);
|
ipcoListPtr, list.dwSize);
|
||||||
int returnvalue = 0; // ERROR_SUCCESS
|
var returnvalue = 0; // ERROR_SUCCESS
|
||||||
if (!isSuccess)
|
if (!isSuccess)
|
||||||
{ // get the error codes, they might be helpful
|
{ // get the error codes, they might be helpful
|
||||||
returnvalue = Marshal.GetLastPInvokeError();
|
returnvalue = Marshal.GetLastPInvokeError();
|
||||||
@@ -172,12 +169,15 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
// Notify the system that the registry settings have been changed and cause them to be refreshed
|
||||||
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
|
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_SETTINGS_CHANGED, nint.Zero, 0);
|
||||||
NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
|
_ = NativeMethods.InternetSetOption(nint.Zero, InternetOption.INTERNET_OPTION_REFRESH, nint.Zero, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FREE the data ASAP
|
// FREE the data ASAP
|
||||||
if (list.szConnection != nint.Zero) Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
if (list.szConnection != nint.Zero)
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(list.szConnection); // release mem 3
|
||||||
|
}
|
||||||
if (optionCount > 1)
|
if (optionCount > 1)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
Marshal.FreeHGlobal(options[1].m_Value.m_StringPtr); // release mem 1
|
||||||
@@ -204,18 +204,18 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
/// <exception cref="ApplicationException">Error message with win32 error code</exception>
|
||||||
private static IEnumerable<string> EnumerateRasEntries()
|
private static IEnumerable<string> EnumerateRasEntries()
|
||||||
{
|
{
|
||||||
int entries = 0;
|
var entries = 0;
|
||||||
// attempt to query with 1 entry buffer
|
// attempt to query with 1 entry buffer
|
||||||
RASENTRYNAME[] rasEntryNames = new RASENTRYNAME[1];
|
var rasEntryNames = new RASENTRYNAME[1];
|
||||||
int bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
var bufferSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||||
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
rasEntryNames[0].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||||
|
|
||||||
uint result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
var result = NativeMethods.RasEnumEntries(null, null, rasEntryNames, ref bufferSize, ref entries);
|
||||||
// increase buffer if the buffer is not large enough
|
// increase buffer if the buffer is not large enough
|
||||||
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
|
if (result == (uint)ErrorCode.ERROR_BUFFER_TOO_SMALL)
|
||||||
{
|
{
|
||||||
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
|
rasEntryNames = new RASENTRYNAME[bufferSize / Marshal.SizeOf(typeof(RASENTRYNAME))];
|
||||||
for (int i = 0; i < rasEntryNames.Length; i++)
|
for (var i = 0; i < rasEntryNames.Length; i++)
|
||||||
{
|
{
|
||||||
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
rasEntryNames[i].dwSize = Marshal.SizeOf(typeof(RASENTRYNAME));
|
||||||
}
|
}
|
||||||
@@ -225,7 +225,7 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
if (result == 0)
|
if (result == 0)
|
||||||
{
|
{
|
||||||
var entryNames = new List<string>();
|
var entryNames = new List<string>();
|
||||||
for (int i = 0; i < entries; i++)
|
for (var i = 0; i < entries; i++)
|
||||||
{
|
{
|
||||||
entryNames.Add(rasEntryNames[i].szEntryName);
|
entryNames.Add(rasEntryNames[i].szEntryName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
using PacLib;
|
namespace ServiceLib.Handler.SysProxy
|
||||||
|
|
||||||
namespace ServiceLib.Handler.SysProxy
|
|
||||||
{
|
{
|
||||||
public static class SysProxyHandler
|
public static class SysProxyHandler
|
||||||
{
|
{
|
||||||
|
private static readonly string _tag = "SysProxyHandler";
|
||||||
|
|
||||||
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
|
public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
|
||||||
{
|
{
|
||||||
var type = config.SystemProxyItem.SysProxyType;
|
var type = config.SystemProxyItem.SysProxyType;
|
||||||
@@ -15,8 +15,8 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.http);
|
var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
||||||
var portSocks = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
|
var exceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||||
if (port <= 0)
|
if (port <= 0)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -25,16 +25,16 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
{
|
{
|
||||||
case ESysProxyType.ForcedChange when Utils.IsWindows():
|
case ESysProxyType.ForcedChange when Utils.IsWindows():
|
||||||
{
|
{
|
||||||
GetWindowsProxyString(config, port, portSocks, out var strProxy, out var strExceptions);
|
GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
|
||||||
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESysProxyType.ForcedChange when Utils.IsLinux():
|
case ESysProxyType.ForcedChange when Utils.IsLinux():
|
||||||
await ProxySettingLinux.SetProxy(Global.Loopback, port);
|
await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESysProxyType.ForcedChange when Utils.IsOSX():
|
case ESysProxyType.ForcedChange when Utils.IsOSX():
|
||||||
await ProxySettingOSX.SetProxy(Global.Loopback, port);
|
await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ESysProxyType.ForcedClear when Utils.IsWindows():
|
case ESysProxyType.ForcedClear when Utils.IsWindows():
|
||||||
@@ -61,21 +61,21 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logging.SaveLog(ex.Message, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void GetWindowsProxyString(Config config, int port, int portSocks, out string strProxy, out string strExceptions)
|
private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
|
||||||
{
|
{
|
||||||
strExceptions = "";
|
strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
|
||||||
if (config.SystemProxyItem.NotProxyLocalAddress)
|
if (config.SystemProxyItem.NotProxyLocalAddress)
|
||||||
{
|
{
|
||||||
strExceptions = $"<local>;{config.ConstItem.DefIEProxyExceptions};{config.SystemProxyItem.SystemProxyExceptions}";
|
strExceptions = $"<local>;{strExceptions}";
|
||||||
}
|
}
|
||||||
|
|
||||||
strProxy = string.Empty;
|
strProxy = string.Empty;
|
||||||
if (Utils.IsNullOrEmpty(config.SystemProxyItem.SystemProxyAdvancedProtocol))
|
if (config.SystemProxyItem.SystemProxyAdvancedProtocol.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
strProxy = $"{Global.Loopback}:{port}";
|
strProxy = $"{Global.Loopback}:{port}";
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ namespace ServiceLib.Handler.SysProxy
|
|||||||
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
|
strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
|
||||||
.Replace("{ip}", Global.Loopback)
|
.Replace("{ip}", Global.Loopback)
|
||||||
.Replace("{http_port}", port.ToString())
|
.Replace("{http_port}", port.ToString())
|
||||||
.Replace("{socks_port}", portSocks.ToString());
|
.Replace("{socks_port}", port.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
{
|
{
|
||||||
public class TaskHandler
|
public class TaskHandler
|
||||||
{
|
{
|
||||||
@@ -7,65 +7,91 @@
|
|||||||
|
|
||||||
public void RegUpdateTask(Config config, Action<bool, string> updateFunc)
|
public void RegUpdateTask(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
Task.Run(() => UpdateTaskRunSubscription(config, updateFunc));
|
Task.Run(() => ScheduledTasks(config, updateFunc));
|
||||||
Task.Run(() => UpdateTaskRunGeo(config, updateFunc));
|
}
|
||||||
|
|
||||||
|
private async Task ScheduledTasks(Config config, Action<bool, string> updateFunc)
|
||||||
|
{
|
||||||
|
Logging.SaveLog("Setup Scheduled Tasks");
|
||||||
|
|
||||||
|
var numOfExecuted = 1;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
//1 minute
|
||||||
|
await Task.Delay(1000 * 60);
|
||||||
|
|
||||||
|
//Execute once 1 minute
|
||||||
|
await UpdateTaskRunSubscription(config, updateFunc);
|
||||||
|
|
||||||
|
//Execute once 20 minute
|
||||||
|
if (numOfExecuted % 20 == 0)
|
||||||
|
{
|
||||||
|
//Logging.SaveLog("Execute save config");
|
||||||
|
|
||||||
|
await ConfigHandler.SaveConfig(config);
|
||||||
|
await ProfileExHandler.Instance.SaveTo();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Execute once 1 hour
|
||||||
|
if (numOfExecuted % 60 == 0)
|
||||||
|
{
|
||||||
|
//Logging.SaveLog("Execute delete expired files");
|
||||||
|
|
||||||
|
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
|
||||||
|
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
|
||||||
|
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
|
||||||
|
|
||||||
|
//Check once 1 hour
|
||||||
|
await UpdateTaskRunGeo(config, numOfExecuted / 60, updateFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
numOfExecuted++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc)
|
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc)
|
||||||
{
|
|
||||||
await Task.Delay(60000);
|
|
||||||
Logging.SaveLog("UpdateTaskRunSubscription");
|
|
||||||
|
|
||||||
var updateHandle = new UpdateService();
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
|
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
|
||||||
var lstSubs = (await AppHandler.Instance.SubItems())
|
var lstSubs = (await AppHandler.Instance.SubItems())?
|
||||||
.Where(t => t.AutoUpdateInterval > 0)
|
.Where(t => t.AutoUpdateInterval > 0)
|
||||||
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
|
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
if (lstSubs is not { Count: > 0 })
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logging.SaveLog("Execute update subscription");
|
||||||
|
var updateHandle = new UpdateService();
|
||||||
|
|
||||||
foreach (var item in lstSubs)
|
foreach (var item in lstSubs)
|
||||||
{
|
{
|
||||||
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
|
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
|
||||||
{
|
{
|
||||||
updateFunc?.Invoke(success, msg);
|
updateFunc?.Invoke(success, msg);
|
||||||
if (success)
|
if (success)
|
||||||
Logging.SaveLog("subscription" + msg);
|
{
|
||||||
|
Logging.SaveLog($"Update subscription end. {msg}");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
item.UpdateTime = updateTime;
|
item.UpdateTime = updateTime;
|
||||||
await ConfigHandler.AddSubItem(config, item);
|
await ConfigHandler.AddSubItem(config, item);
|
||||||
|
await Task.Delay(1000);
|
||||||
await Task.Delay(5000);
|
|
||||||
}
|
|
||||||
await Task.Delay(60000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> updateFunc)
|
private async Task UpdateTaskRunGeo(Config config, int hours, Action<bool, string> updateFunc)
|
||||||
{
|
{
|
||||||
var autoUpdateGeoTime = DateTime.Now;
|
if (config.GuiItem.AutoUpdateInterval > 0 && hours > 0 && hours % config.GuiItem.AutoUpdateInterval == 0)
|
||||||
|
{
|
||||||
//await Task.Delay(1000 * 120);
|
Logging.SaveLog("Execute update geo files");
|
||||||
Logging.SaveLog("UpdateTaskRunGeo");
|
|
||||||
|
|
||||||
var updateHandle = new UpdateService();
|
var updateHandle = new UpdateService();
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
await Task.Delay(1000 * 3600);
|
|
||||||
|
|
||||||
var dtNow = DateTime.Now;
|
|
||||||
if (config.GuiItem.AutoUpdateInterval > 0)
|
|
||||||
{
|
|
||||||
if ((dtNow - autoUpdateGeoTime).Hours % config.GuiItem.AutoUpdateInterval == 0)
|
|
||||||
{
|
|
||||||
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
|
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
|
||||||
{
|
{
|
||||||
updateFunc?.Invoke(false, msg);
|
updateFunc?.Invoke(false, msg);
|
||||||
});
|
});
|
||||||
autoUpdateGeoTime = dtNow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using WebDav;
|
using WebDav;
|
||||||
|
|
||||||
namespace ServiceLib.Handler
|
namespace ServiceLib.Handler
|
||||||
@@ -8,12 +8,12 @@ namespace ServiceLib.Handler
|
|||||||
private static readonly Lazy<WebDavHandler> _instance = new(() => new());
|
private static readonly Lazy<WebDavHandler> _instance = new(() => new());
|
||||||
public static WebDavHandler Instance => _instance.Value;
|
public static WebDavHandler Instance => _instance.Value;
|
||||||
|
|
||||||
private Config? _config;
|
private readonly Config? _config;
|
||||||
private WebDavClient? _client;
|
private WebDavClient? _client;
|
||||||
private string? _lastDescription;
|
private string? _lastDescription;
|
||||||
private string _webDir = Global.AppName + "_backup";
|
private string _webDir = Global.AppName + "_backup";
|
||||||
private readonly string _webFileName = "backup.zip";
|
private readonly string _webFileName = "backup.zip";
|
||||||
private string _logTitle = "WebDav--";
|
private readonly string _tag = "WebDav--";
|
||||||
|
|
||||||
public WebDavHandler()
|
public WebDavHandler()
|
||||||
{
|
{
|
||||||
@@ -61,7 +61,10 @@ namespace ServiceLib.Handler
|
|||||||
|
|
||||||
private async Task<bool> TryCreateDir()
|
private async Task<bool> TryCreateDir()
|
||||||
{
|
{
|
||||||
if (_client is null) return false;
|
if (_client is null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result2 = await _client.Mkcol(_webDir);
|
var result2 = await _client.Mkcol(_webDir);
|
||||||
@@ -81,13 +84,13 @@ namespace ServiceLib.Handler
|
|||||||
private void SaveLog(string desc)
|
private void SaveLog(string desc)
|
||||||
{
|
{
|
||||||
_lastDescription = desc;
|
_lastDescription = desc;
|
||||||
Logging.SaveLog(_logTitle + desc);
|
Logging.SaveLog(_tag + desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveLog(Exception ex)
|
private void SaveLog(Exception ex)
|
||||||
{
|
{
|
||||||
_lastDescription = ex.Message;
|
_lastDescription = ex.Message;
|
||||||
Logging.SaveLog(_logTitle, ex);
|
Logging.SaveLog(_tag, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> CheckConnection()
|
public async Task<bool> CheckConnection()
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
public string? destinationPort { get; set; }
|
public string? destinationPort { get; set; }
|
||||||
public string? host { get; set; }
|
public string? host { get; set; }
|
||||||
public string? nsMode { get; set; }
|
public string? nsMode { get; set; }
|
||||||
public object uid { get; set; }
|
public object? uid { get; set; }
|
||||||
public string? process { get; set; }
|
public string? process { get; set; }
|
||||||
public string? processPath { get; set; }
|
public string? processPath { get; set; }
|
||||||
public string? remoteDestination { get; set; }
|
public string? remoteDestination { get; set; }
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
public SystemProxyItem SystemProxyItem { get; set; }
|
public SystemProxyItem SystemProxyItem { get; set; }
|
||||||
public WebDavItem WebDavItem { get; set; }
|
public WebDavItem WebDavItem { get; set; }
|
||||||
public CheckUpdateItem CheckUpdateItem { get; set; }
|
public CheckUpdateItem CheckUpdateItem { get; set; }
|
||||||
|
public Fragment4RayItem? Fragment4RayItem { get; set; }
|
||||||
public List<InItem> Inbound { get; set; }
|
public List<InItem> Inbound { get; set; }
|
||||||
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreBasicItem
|
public class CoreBasicItem
|
||||||
@@ -24,21 +24,16 @@
|
|||||||
public class InItem
|
public class InItem
|
||||||
{
|
{
|
||||||
public int LocalPort { get; set; }
|
public int LocalPort { get; set; }
|
||||||
|
|
||||||
public string Protocol { get; set; }
|
public string Protocol { get; set; }
|
||||||
|
|
||||||
public bool UdpEnabled { get; set; }
|
public bool UdpEnabled { get; set; }
|
||||||
|
|
||||||
public bool SniffingEnabled { get; set; } = true;
|
public bool SniffingEnabled { get; set; } = true;
|
||||||
public List<string>? DestOverride { get; set; } = ["http", "tls"];
|
public List<string>? DestOverride { get; set; } = ["http", "tls"];
|
||||||
public bool RouteOnly { get; set; }
|
public bool RouteOnly { get; set; }
|
||||||
public bool AllowLANConn { get; set; }
|
public bool AllowLANConn { get; set; }
|
||||||
|
|
||||||
public bool NewPort4LAN { get; set; }
|
public bool NewPort4LAN { get; set; }
|
||||||
|
|
||||||
public string User { get; set; }
|
public string User { get; set; }
|
||||||
|
|
||||||
public string Pass { get; set; }
|
public string Pass { get; set; }
|
||||||
|
public bool SecondLocalPortEnabled { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -72,21 +67,13 @@
|
|||||||
public class GUIItem
|
public class GUIItem
|
||||||
{
|
{
|
||||||
public bool AutoRun { get; set; }
|
public bool AutoRun { get; set; }
|
||||||
|
|
||||||
public bool EnableStatistics { get; set; }
|
public bool EnableStatistics { get; set; }
|
||||||
|
public bool DisplayRealTimeSpeed { get; set; }
|
||||||
public bool KeepOlderDedupl { get; set; }
|
public bool KeepOlderDedupl { get; set; }
|
||||||
|
|
||||||
public bool IgnoreGeoUpdateCore { get; set; } = true;
|
|
||||||
|
|
||||||
public int AutoUpdateInterval { get; set; }
|
public int AutoUpdateInterval { get; set; }
|
||||||
|
|
||||||
public bool EnableSecurityProtocolTls13 { get; set; }
|
public bool EnableSecurityProtocolTls13 { get; set; }
|
||||||
|
|
||||||
public int TrayMenuServersLimit { get; set; } = 20;
|
public int TrayMenuServersLimit { get; set; } = 20;
|
||||||
|
|
||||||
public bool EnableHWA { get; set; } = false;
|
public bool EnableHWA { get; set; } = false;
|
||||||
|
|
||||||
public bool EnableLog { get; set; } = true;
|
public bool EnableLog { get; set; } = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,9 +94,8 @@
|
|||||||
public double MainGirdHeight1 { get; set; }
|
public double MainGirdHeight1 { get; set; }
|
||||||
public double MainGirdHeight2 { get; set; }
|
public double MainGirdHeight2 { get; set; }
|
||||||
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
public EGirdOrientation MainGirdOrientation { get; set; } = EGirdOrientation.Vertical;
|
||||||
public bool ColorModeDark { get; set; }
|
|
||||||
public bool FollowSystemTheme { get; set; }
|
|
||||||
public string? ColorPrimaryName { get; set; }
|
public string? ColorPrimaryName { get; set; }
|
||||||
|
public string? CurrentTheme { get; set; }
|
||||||
public string CurrentLanguage { get; set; }
|
public string CurrentLanguage { get; set; }
|
||||||
public string CurrentFontFamily { get; set; }
|
public string CurrentFontFamily { get; set; }
|
||||||
public int CurrentFontSize { get; set; }
|
public int CurrentFontSize { get; set; }
|
||||||
@@ -124,8 +110,7 @@
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class ConstItem
|
public class ConstItem
|
||||||
{
|
{
|
||||||
public string DefIEProxyExceptions { get; set; }
|
public string? SubConvertUrl { get; set; }
|
||||||
public string SubConvertUrl { get; set; } = string.Empty;
|
|
||||||
public string? GeoSourceUrl { get; set; }
|
public string? GeoSourceUrl { get; set; }
|
||||||
public string? SrsSourceUrl { get; set; }
|
public string? SrsSourceUrl { get; set; }
|
||||||
public string? RouteRulesTemplateSourceUrl { get; set; }
|
public string? RouteRulesTemplateSourceUrl { get; set; }
|
||||||
@@ -171,6 +156,7 @@
|
|||||||
public int SpeedTestTimeout { get; set; }
|
public int SpeedTestTimeout { get; set; }
|
||||||
public string SpeedTestUrl { get; set; }
|
public string SpeedTestUrl { get; set; }
|
||||||
public string SpeedPingTestUrl { get; set; }
|
public string SpeedPingTestUrl { get; set; }
|
||||||
|
public int MixedConcurrencyCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -211,6 +197,7 @@
|
|||||||
{
|
{
|
||||||
public int UpMbps { get; set; }
|
public int UpMbps { get; set; }
|
||||||
public int DownMbps { get; set; }
|
public int DownMbps { get; set; }
|
||||||
|
public int HopInterval { get; set; } = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
@@ -222,7 +209,6 @@
|
|||||||
public int ProxiesSorting { get; set; }
|
public int ProxiesSorting { get; set; }
|
||||||
public bool ProxiesAutoRefresh { get; set; }
|
public bool ProxiesAutoRefresh { get; set; }
|
||||||
public int ProxiesAutoDelayTestInterval { get; set; } = 10;
|
public int ProxiesAutoDelayTestInterval { get; set; } = 10;
|
||||||
public int ConnectionsSorting { get; set; }
|
|
||||||
public bool ConnectionsAutoRefresh { get; set; }
|
public bool ConnectionsAutoRefresh { get; set; }
|
||||||
public int ConnectionsRefreshInterval { get; set; } = 2;
|
public int ConnectionsRefreshInterval { get; set; } = 2;
|
||||||
}
|
}
|
||||||
@@ -251,4 +237,12 @@
|
|||||||
public bool CheckPreReleaseUpdate { get; set; }
|
public bool CheckPreReleaseUpdate { get; set; }
|
||||||
public List<string>? SelectedCoreTypes { get; set; }
|
public List<string>? SelectedCoreTypes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Fragment4RayItem
|
||||||
|
{
|
||||||
|
public string? Packets { get; set; }
|
||||||
|
public string? Length { get; set; }
|
||||||
|
public string? Interval { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class CoreInfo
|
public class CoreInfo
|
||||||
@@ -12,8 +12,10 @@
|
|||||||
public string? DownloadUrlWinArm64 { get; set; }
|
public string? DownloadUrlWinArm64 { get; set; }
|
||||||
public string? DownloadUrlLinux64 { get; set; }
|
public string? DownloadUrlLinux64 { get; set; }
|
||||||
public string? DownloadUrlLinuxArm64 { get; set; }
|
public string? DownloadUrlLinuxArm64 { get; set; }
|
||||||
|
public string? DownloadUrlOSX64 { get; set; }
|
||||||
|
public string? DownloadUrlOSXArm64 { get; set; }
|
||||||
public string? Match { get; set; }
|
public string? Match { get; set; }
|
||||||
public string? VersionArg { get; set; }
|
public string? VersionArg { get; set; }
|
||||||
public bool RedirectInfo { get; set; }
|
public bool AbsolutePath { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
@@ -11,5 +11,6 @@ namespace ServiceLib.Models
|
|||||||
public int Delay { get; set; }
|
public int Delay { get; set; }
|
||||||
public decimal Speed { get; set; }
|
public decimal Speed { get; set; }
|
||||||
public int Sort { get; set; }
|
public int Sort { get; set; }
|
||||||
|
public string? Message { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
@@ -48,12 +48,12 @@ namespace ServiceLib.Models
|
|||||||
|
|
||||||
public List<string>? GetAlpn()
|
public List<string>? GetAlpn()
|
||||||
{
|
{
|
||||||
return Utils.IsNullOrEmpty(Alpn) ? null : Utils.String2List(Alpn);
|
return Alpn.IsNullOrEmpty() ? null : Utils.String2List(Alpn);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetNetwork()
|
public string GetNetwork()
|
||||||
{
|
{
|
||||||
if (Utils.IsNullOrEmpty(Network) || !Global.Networks.Contains(Network))
|
if (Network.IsNullOrEmpty() || !Global.Networks.Contains(Network))
|
||||||
{
|
{
|
||||||
return Global.DefaultNetwork;
|
return Global.DefaultNetwork;
|
||||||
}
|
}
|
||||||
@@ -64,11 +64,11 @@ namespace ServiceLib.Models
|
|||||||
|
|
||||||
[PrimaryKey]
|
[PrimaryKey]
|
||||||
public string IndexId { get; set; }
|
public string IndexId { get; set; }
|
||||||
|
|
||||||
public EConfigType ConfigType { get; set; }
|
public EConfigType ConfigType { get; set; }
|
||||||
public int ConfigVersion { get; set; }
|
public int ConfigVersion { get; set; }
|
||||||
public string Address { get; set; }
|
public string Address { get; set; }
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
|
public string Ports { get; set; }
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public int AlterId { get; set; }
|
public int AlterId { get; set; }
|
||||||
public string Security { get; set; }
|
public string Security { get; set; }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ServerTestItem
|
public class ServerTestItem
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
public EConfigType ConfigType { get; set; }
|
public EConfigType ConfigType { get; set; }
|
||||||
public bool AllowTest { get; set; }
|
public bool AllowTest { get; set; }
|
||||||
public int Delay { get; set; }
|
public int QueueNum { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace ServiceLib.Models
|
namespace ServiceLib.Models
|
||||||
{
|
{
|
||||||
public class SingboxConfig
|
public class SingboxConfig
|
||||||
{
|
{
|
||||||
@@ -101,21 +101,23 @@
|
|||||||
public string tag { get; set; }
|
public string tag { get; set; }
|
||||||
public string? server { get; set; }
|
public string? server { get; set; }
|
||||||
public int? server_port { get; set; }
|
public int? server_port { get; set; }
|
||||||
public string uuid { get; set; }
|
public List<string>? server_ports { get; set; }
|
||||||
public string security { get; set; }
|
public string? uuid { get; set; }
|
||||||
|
public string? security { get; set; }
|
||||||
public int? alter_id { get; set; }
|
public int? alter_id { get; set; }
|
||||||
public string flow { get; set; }
|
public string? flow { get; set; }
|
||||||
|
public string? hop_interval { get; set; }
|
||||||
public int? up_mbps { get; set; }
|
public int? up_mbps { get; set; }
|
||||||
public int? down_mbps { get; set; }
|
public int? down_mbps { get; set; }
|
||||||
public string auth_str { get; set; }
|
public string? auth_str { get; set; }
|
||||||
public int? recv_window_conn { get; set; }
|
public int? recv_window_conn { get; set; }
|
||||||
public int? recv_window { get; set; }
|
public int? recv_window { get; set; }
|
||||||
public bool? disable_mtu_discovery { get; set; }
|
public bool? disable_mtu_discovery { get; set; }
|
||||||
public string? detour { get; set; }
|
public string? detour { get; set; }
|
||||||
public string method { get; set; }
|
public string? method { get; set; }
|
||||||
public string username { get; set; }
|
public string? username { get; set; }
|
||||||
public string password { get; set; }
|
public string? password { get; set; }
|
||||||
public string congestion_control { get; set; }
|
public string? congestion_control { get; set; }
|
||||||
public string? version { get; set; }
|
public string? version { get; set; }
|
||||||
public string? network { get; set; }
|
public string? network { get; set; }
|
||||||
public string? packet_encoding { get; set; }
|
public string? packet_encoding { get; set; }
|
||||||
|
|||||||
@@ -4,23 +4,15 @@ namespace ServiceLib.Models
|
|||||||
{
|
{
|
||||||
public class V2rayConfig
|
public class V2rayConfig
|
||||||
{
|
{
|
||||||
public string? remarks { get; set; }
|
|
||||||
|
|
||||||
public Log4Ray log { get; set; }
|
public Log4Ray log { get; set; }
|
||||||
|
|
||||||
public List<Inbounds4Ray> inbounds { get; set; }
|
|
||||||
|
|
||||||
public List<Outbounds4Ray> outbounds { get; set; }
|
|
||||||
|
|
||||||
public Stats4Ray? stats { get; set; }
|
|
||||||
|
|
||||||
public Metrics4Ray? metrics { get; set; }
|
|
||||||
|
|
||||||
public Policy4Ray? policy { get; set; }
|
|
||||||
|
|
||||||
public object dns { get; set; }
|
public object dns { get; set; }
|
||||||
|
public List<Inbounds4Ray> inbounds { get; set; }
|
||||||
|
public List<Outbounds4Ray> outbounds { get; set; }
|
||||||
public Routing4Ray routing { get; set; }
|
public Routing4Ray routing { get; set; }
|
||||||
|
public Metrics4Ray? metrics { get; set; }
|
||||||
|
public Policy4Ray? policy { get; set; }
|
||||||
|
public Stats4Ray? stats { get; set; }
|
||||||
|
public string? remarks { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Stats4Ray
|
public class Stats4Ray
|
||||||
@@ -299,6 +291,8 @@ namespace ServiceLib.Models
|
|||||||
public object request { get; set; }
|
public object request { get; set; }
|
||||||
|
|
||||||
public object response { get; set; }
|
public object response { get; set; }
|
||||||
|
|
||||||
|
public string? domain { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KcpSettings4Ray
|
public class KcpSettings4Ray
|
||||||
@@ -324,7 +318,8 @@ namespace ServiceLib.Models
|
|||||||
|
|
||||||
public class WsSettings4Ray
|
public class WsSettings4Ray
|
||||||
{
|
{
|
||||||
public string path { get; set; }
|
public string? path { get; set; }
|
||||||
|
public string? host { get; set; }
|
||||||
|
|
||||||
public Headers4Ray headers { get; set; }
|
public Headers4Ray headers { get; set; }
|
||||||
}
|
}
|
||||||
@@ -349,21 +344,9 @@ namespace ServiceLib.Models
|
|||||||
public string? path { get; set; }
|
public string? path { get; set; }
|
||||||
public string? host { get; set; }
|
public string? host { get; set; }
|
||||||
public string? mode { get; set; }
|
public string? mode { get; set; }
|
||||||
public string? scMaxEachPostBytes { get; set; }
|
|
||||||
public string? scMaxConcurrentPosts { get; set; }
|
|
||||||
public string? scMinPostsIntervalMs { get; set; }
|
|
||||||
public Xmux4Ray? xmux { get; set; }
|
|
||||||
public object? extra { get; set; }
|
public object? extra { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Xmux4Ray
|
|
||||||
{
|
|
||||||
public int? maxConcurrency { get; set; }
|
|
||||||
public int? maxConnections { get; set; }
|
|
||||||
public int? cMaxReuseTimes { get; set; }
|
|
||||||
public int? cMaxLifetimeMs { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class HttpSettings4Ray
|
public class HttpSettings4Ray
|
||||||
{
|
{
|
||||||
public string? path { get; set; }
|
public string? path { get; set; }
|
||||||
|
|||||||
262
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
262
v2rayN/ServiceLib/Resx/ResUI.Designer.cs
generated
@@ -61,7 +61,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Do you want to append rules? Choose yes to append, choose otherwise to replace 的本地化字符串。
|
/// 查找类似 Do you want to append rules? Choose yes to append, choose otherwise to replace. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string AddBatchRoutingRulesYesNo {
|
public static string AddBatchRoutingRulesYesNo {
|
||||||
get {
|
get {
|
||||||
@@ -196,7 +196,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Failed to run Core, please see the log 的本地化字符串。
|
/// 查找类似 Failed to run Core, please check the prompt information 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string FailedToRunCore {
|
public static string FailedToRunCore {
|
||||||
get {
|
get {
|
||||||
@@ -403,7 +403,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Custom Icon 的本地化字符串。
|
/// 查找类似 Custom icon 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvCustomIcon {
|
public static string LvCustomIcon {
|
||||||
get {
|
get {
|
||||||
@@ -610,7 +610,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 URL(Optional) 的本地化字符串。
|
/// 查找类似 URL (optional) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string LvUrl {
|
public static string LvUrl {
|
||||||
get {
|
get {
|
||||||
@@ -843,6 +843,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Copy proxy command to clipboard 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuCopyProxyCmdToClipboard {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuCopyProxyCmdToClipboard", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Clone selected server 的本地化字符串。
|
/// 查找类似 Clone selected server 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -942,15 +951,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Import old config (guiNConfig) 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuImportOldGuiConfig {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuImportOldGuiConfig", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Import Rules From Clipboard 的本地化字符串。
|
/// 查找类似 Import Rules From Clipboard 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1006,7 +1006,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 One-click multi test Latency and speed (Ctrl+E) 的本地化字符串。
|
/// 查找类似 One-click multi-test latency and speed (Ctrl+E) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuMixedTestServer {
|
public static string menuMixedTestServer {
|
||||||
get {
|
get {
|
||||||
@@ -1248,6 +1248,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Iran 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRegionalPresetsIran {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRegionalPresetsIran", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Russia 的本地化字符串。
|
/// 查找类似 Russia 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1302,6 +1311,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remove invalid by test results 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuRemoveInvalidServerResult {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuRemoveInvalidServerResult", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Remove selected servers (Delete) 的本地化字符串。
|
/// 查找类似 Remove selected servers (Delete) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1339,7 +1357,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Import Advanced Rules 的本地化字符串。
|
/// 查找类似 Import Rules 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuRoutingAdvancedImportRules {
|
public static string menuRoutingAdvancedImportRules {
|
||||||
get {
|
get {
|
||||||
@@ -1357,7 +1375,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Set as active rule(Enter) 的本地化字符串。
|
/// 查找类似 Set as active rule (Enter) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string menuRoutingAdvancedSetDefault {
|
public static string menuRoutingAdvancedSetDefault {
|
||||||
get {
|
get {
|
||||||
@@ -1527,15 +1545,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Save Interface Layout 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuStorageUI {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuStorageUI", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Add 的本地化字符串。
|
/// 查找类似 Add 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1680,6 +1689,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 By test result 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuTestServerResult {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuTestServerResult", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} Website 的本地化字符串。
|
/// 查找类似 {0} Website 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1689,15 +1707,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Clear original subscription content 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string MsgClearSubscription {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("MsgClearSubscription", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Download GeoFile: {0} successfully 的本地化字符串。
|
/// 查找类似 Download GeoFile: {0} successfully 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2004,6 +2013,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Removed {0} invalid test results. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string RemoveInvalidServerResultTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("RemoveInvalidServerResultTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Are you sure to remove the rules? 的本地化字符串。
|
/// 查找类似 Are you sure to remove the rules? 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2094,6 +2112,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Starting retesting failed parts, {0} remaining. Press ESC to terminate... 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string SpeedtestingTestFailedPart {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SpeedtestingTestFailedPart", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Waiting for testing (press ESC to terminate)... 的本地化字符串。
|
/// 查找类似 Waiting for testing (press ESC to terminate)... 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2195,7 +2222,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 AutoRefresh 的本地化字符串。
|
/// 查找类似 Auto refresh 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbAutoRefresh {
|
public static string TbAutoRefresh {
|
||||||
get {
|
get {
|
||||||
@@ -2204,7 +2231,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Auto ScrollToEnd 的本地化字符串。
|
/// 查找类似 Auto scroll to end 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbAutoScrollToEnd {
|
public static string TbAutoScrollToEnd {
|
||||||
get {
|
get {
|
||||||
@@ -2294,7 +2321,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Support DnsObject, Click to view the document 的本地化字符串。
|
/// 查找类似 Supports DnsObject; Click to view documentation 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbDnsObjectDoc {
|
public static string TbDnsObjectDoc {
|
||||||
get {
|
get {
|
||||||
@@ -2347,15 +2374,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Enable advanced function 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbenableRoutingAdvanced {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbenableRoutingAdvanced", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enable Tun 的本地化字符串。
|
/// 查找类似 Enable Tun 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2393,7 +2411,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Set directly by pressing the keyboard, take effect after restart 的本地化字符串。
|
/// 查找类似 Set directly by pressing the keyboard; Takes effect after restart 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbGlobalHotkeySettingTip {
|
public static string TbGlobalHotkeySettingTip {
|
||||||
get {
|
get {
|
||||||
@@ -2465,7 +2483,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Address(Ip,Ipv6) 的本地化字符串。
|
/// 查找类似 Address(Ipv4,Ipv6) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbLocalAddress {
|
public static string TbLocalAddress {
|
||||||
get {
|
get {
|
||||||
@@ -2518,6 +2536,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Server port range 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbPorts7 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbPorts7", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Will cover the port, separate with commas (,) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbPorts7Tips {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbPorts7Tips", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Socks port 的本地化字符串。
|
/// 查找类似 Socks port 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2599,6 +2635,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 socks: local port, socks2: second local port, socks3: LAN port 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbRoutingInboundTagTips {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbRoutingInboundTagTips", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Domain 的本地化字符串。
|
/// 查找类似 Domain 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2663,7 +2708,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 *Set the rules, separated by commas (,); The comma in the regular is replaced by <COMMA> 的本地化字符串。
|
/// 查找类似 *Separate rules by commas (,); For a literal comma use <COMMA>; Prefix # to ignore a rule 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbRoutingTips {
|
public static string TbRoutingTips {
|
||||||
get {
|
get {
|
||||||
@@ -2771,7 +2816,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Automatic update interval of Geo (hours) 的本地化字符串。
|
/// 查找类似 Automatic update interval for Geo files (hours) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsAutoUpdateInterval {
|
public static string TbSettingsAutoUpdateInterval {
|
||||||
get {
|
get {
|
||||||
@@ -2797,15 +2842,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Dark Mode 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsColorMode {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsColorMode", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Core: basic settings 的本地化字符串。
|
/// 查找类似 Core: basic settings 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2852,7 +2888,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 FontFamily(Require restart) 的本地化字符串。
|
/// 查找类似 Font family (requires restart) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsCurrentFontFamily {
|
public static string TbSettingsCurrentFontFamily {
|
||||||
get {
|
get {
|
||||||
@@ -2861,7 +2897,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Install the font to the system and restart the settings 的本地化字符串。
|
/// 查找类似 Install the font to the system, select or fill in the font name, restart the settings 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsCurrentFontFamilyLinuxTip {
|
public static string TbSettingsCurrentFontFamilyLinuxTip {
|
||||||
get {
|
get {
|
||||||
@@ -2870,7 +2906,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Copy the font TTF/TTC file to the directory guiFonts, restart the settings 的本地化字符串。
|
/// 查找类似 Copy the font TTF/TTC file to the directory guiFonts; Reopen the settings window 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsCurrentFontFamilyTip {
|
public static string TbSettingsCurrentFontFamilyTip {
|
||||||
get {
|
get {
|
||||||
@@ -2914,6 +2950,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Sniffing type 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsDestOverride {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsDestOverride", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Display real-time speed (requires restart) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsDisplayRealTimeSpeed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsDisplayRealTimeSpeed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Outbound DNS address 的本地化字符串。
|
/// 查找类似 Outbound DNS address 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2942,7 +2996,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Double-click server make active 的本地化字符串。
|
/// 查找类似 Double-clicking server makes it active 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsDoubleClick2Activate {
|
public static string TbSettingsDoubleClick2Activate {
|
||||||
get {
|
get {
|
||||||
@@ -2951,7 +3005,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Automatically adjust column width after updating subscription 的本地化字符串。
|
/// 查找类似 Automatically adjust column width after subscription update 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsEnableAutoAdjustMainLvColWidth {
|
public static string TbSettingsEnableAutoAdjustMainLvColWidth {
|
||||||
get {
|
get {
|
||||||
@@ -2978,7 +3032,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enable Server Drag Drop Sort(Require restart) 的本地化字符串。
|
/// 查找类似 Enable sorting servers by drag-n-drop (requires restart) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsEnableDragDropSort {
|
public static string TbSettingsEnableDragDropSort {
|
||||||
get {
|
get {
|
||||||
@@ -3014,7 +3068,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enable hardware acceleration(Require restart) 的本地化字符串。
|
/// 查找类似 Enable hardware acceleration (requires restart) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsEnableHWA {
|
public static string TbSettingsEnableHWA {
|
||||||
get {
|
get {
|
||||||
@@ -3050,7 +3104,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Exception. Do not use proxy server for addresses beginning with,Use semicolon (;) 的本地化字符串。
|
/// 查找类似 Exclusions: Do not use proxy server for addresses beginning with the following. Use semicolon (;) to separate entries. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsExceptionTip {
|
public static string TbSettingsExceptionTip {
|
||||||
get {
|
get {
|
||||||
@@ -3059,11 +3113,11 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Follow System Theme 的本地化字符串。
|
/// 查找类似 Exclusions: Do not use proxy server for the following addresses. Use comma (,) to separate entries. 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsFollowSystemTheme {
|
public static string TbSettingsExceptionTip2 {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("TbSettingsFollowSystemTheme", resourceCulture);
|
return ResourceManager.GetString("TbSettingsExceptionTip2", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3094,15 +3148,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 HTTP Port 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsHttpPort {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsHttpPort", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Hysteria Max bandwidth (Up/Dw) 的本地化字符串。
|
/// 查找类似 Hysteria Max bandwidth (Up/Dw) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3113,16 +3158,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Ignore Geo files when updating core 的本地化字符串。
|
/// 查找类似 Keep the older when de-duplicating 的本地化字符串。
|
||||||
/// </summary>
|
|
||||||
public static string TbSettingsIgnoreGeoUpdateCore {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("TbSettingsIgnoreGeoUpdateCore", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Keep older when deduplication 的本地化字符串。
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsKeepOlderDedupl {
|
public static string TbSettingsKeepOlderDedupl {
|
||||||
get {
|
get {
|
||||||
@@ -3140,7 +3176,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Linux system sudo password 的本地化字符串。
|
/// 查找类似 System sudo password 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsLinuxSudoPassword {
|
public static string TbSettingsLinuxSudoPassword {
|
||||||
get {
|
get {
|
||||||
@@ -3167,7 +3203,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 The password is encrypted and stored only in local files. 的本地化字符串。
|
/// 查找类似 The password is encrypted and stored only in local files 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsLinuxSudoPasswordTip {
|
public static string TbSettingsLinuxSudoPasswordTip {
|
||||||
get {
|
get {
|
||||||
@@ -3203,7 +3239,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Main layout orientation(Require restart) 的本地化字符串。
|
/// 查找类似 Main layout orientation (requires restart) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsMainGirdOrientation {
|
public static string TbSettingsMainGirdOrientation {
|
||||||
get {
|
get {
|
||||||
@@ -3211,6 +3247,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 The number of concurrent during multi-test 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsMixedConcurrencyCount {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsMixedConcurrencyCount", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
|
/// 查找类似 sing-box Mux Protocol 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3292,6 +3337,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Enable second mixed port 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsSecondLocalPortEnabled {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsSecondLocalPortEnabled", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
|
/// 查找类似 Set Win10 UWP Loopback 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3311,7 +3365,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 SOCKS Port 的本地化字符串。
|
/// 查找类似 Mixed Port 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsSocksPort {
|
public static string TbSettingsSocksPort {
|
||||||
get {
|
get {
|
||||||
@@ -3320,7 +3374,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 http port = +1; Pac port = +4; *ray API port = +5; mihomo API port = +6; 的本地化字符串。
|
/// 查找类似 Pac port = +3; Xray API port = +4; mihomo API port = +5; 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsSocksPortTip {
|
public static string TbSettingsSocksPortTip {
|
||||||
get {
|
get {
|
||||||
@@ -3383,7 +3437,7 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enable Statistics (Require restart) 的本地化字符串。
|
/// 查找类似 Enable traffic statistics (requires restart) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string TbSettingsStatistics {
|
public static string TbSettingsStatistics {
|
||||||
get {
|
get {
|
||||||
@@ -3409,6 +3463,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Theme 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbSettingsTheme {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbSettingsTheme", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Enable Security Protocol TLS v1.3 (subscription/update) 的本地化字符串。
|
/// 查找类似 Enable Security Protocol TLS v1.3 (subscription/update) 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3841,15 +3904,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 You are currently running a standalone package, please manually download the SelfContained.7z file to unzip and overwrite it! 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string UpdateStandalonePackageTip {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("UpdateStandalonePackageTip", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 UpgradeApp does not exist 的本地化字符串。
|
/// 查找类似 UpgradeApp does not exist 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1405
v2rayN/ServiceLib/Resx/ResUI.hu.resx
Normal file
1405
v2rayN/ServiceLib/Resx/ResUI.hu.resx
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user