improve ui

This commit is contained in:
arm64v8a
2022-08-05 17:08:21 +08:00
parent efdac7fa6f
commit 22b042b55b
30 changed files with 983 additions and 41 deletions

View File

@@ -89,15 +89,17 @@ set(PROJECT_SOURCES
3rdparty/qrcodegen.cpp
3rdparty/QtExtKeySequenceEdit.cpp
qv2ray/ui/LogHighlighter.cpp
qv2ray/ui/QvAutoCompleteTextEdit.cpp
qv2ray/utils/HTTPRequestHelper.cpp
qv2ray/components/proxy/QvProxyConfigurator.cpp
qv2ray/ui/widgets/common/QJsonModel.cpp
qv2ray/v2/ui/LogHighlighter.cpp
qv2ray/v2/ui/QvAutoCompleteTextEdit.cpp
qv2ray/v2/utils/HTTPRequestHelper.cpp
qv2ray/v2/components/proxy/QvProxyConfigurator.cpp
qv2ray/v2/ui/widgets/common/QJsonModel.cpp
qv2ray/v2/ui/widgets/editors/w_JsonEditor.cpp
qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp
qv2ray/v2/ui/widgets/editors/w_JsonEditor.ui
qv2ray/ui/widgets/editors/w_JsonEditor.cpp
qv2ray/ui/widgets/editors/w_JsonEditor.hpp
qv2ray/ui/widgets/editors/w_JsonEditor.ui
qv2ray/v3/components/GeositeReader/GeositeReader.cpp
qv2ray/v3/components/GeositeReader/picoproto.cpp
rpc/gRPC.cpp

View File

@@ -1,7 +1,7 @@
#pragma once
#include "qv2ray/wrapper.hpp"
#include "qv2ray/ui/widgets/common/QJsonModel.hpp"
#include "qv2ray/v2/ui/widgets/common/QJsonModel.hpp"
#include "ui_w_JsonEditor.h"

View File

@@ -0,0 +1,42 @@
#include "GeositeReader.hpp"
#include "qv2ray/wrapper.hpp"
#include "picoproto.hpp"
#include <QFile>
#include <QMap>
namespace Qv2ray::components::GeositeReader {
QMap<QString, QStringList> GeositeEntries;
QStringList ReadGeoSiteFromFile(const QString &filepath, bool allowCache) {
if (GeositeEntries.contains(filepath) && allowCache)
return GeositeEntries.value(filepath);
QStringList list;
qInfo() << "Reading geosites from:" << filepath;
QFile f(filepath);
bool opened = f.open(QFile::OpenModeFlag::ReadOnly);
if (!opened) {
qInfo() << "File cannot be opened:" << filepath;
return list;
}
const auto content = f.readAll();
f.close();
{
picoproto::Message root;
root.ParseFromBytes((unsigned char *) content.data(), content.size());
list.reserve(root.GetMessageArray(1).size());
for (const auto &geosite: root.GetMessageArray(1))
list << QString::fromStdString(geosite->GetString(1));
}
qInfo() << "Loaded" << list.count() << "geosite entries from data file.";
list.sort();
GeositeEntries[filepath] = list;
return list;
}
} // namespace Qv2ray::components::geosite

View File

@@ -0,0 +1,7 @@
#pragma once
#include <QString>
namespace Qv2ray::components::GeositeReader {
QStringList ReadGeoSiteFromFile(const QString &filepath, bool allowCache = true);
} // namespace Qv2ray::components::GeositeReader

View File

@@ -0,0 +1,664 @@
/* Copyright 2016 Pete Warden. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "picoproto.hpp"
namespace picoproto
{
namespace
{
// To keep the dependencies down, here's a local copy of the widespread bit_cast
// operator. This is necessary because in practice weird things can happen if
// you just try to use reinterpret_cast.
template<class Dest, class Source>
inline Dest bit_cast(const Source &source)
{
static_assert(sizeof(Dest) == sizeof(Source), "Sizes do not match");
Dest dest;
memcpy(&dest, &source, sizeof(dest));
return dest;
}
// These are defined in:
// https://developers.google.com/protocol-buffers/docs/encoding
enum WireType
{
WIRETYPE_VARINT = 0,
WIRETYPE_64BIT = 1,
WIRETYPE_LENGTH_DELIMITED = 2,
WIRETYPE_GROUP_START = 3,
WIRETYPE_GROUP_END = 4,
WIRETYPE_32BIT = 5,
};
// Pull bytes from the stream, updating the state.
bool ConsumeBytes(uint8_t **current, size_t how_many, size_t *remaining)
{
if (how_many > *remaining)
{
PP_LOG(ERROR) << "ReadBytes overrun!";
return false;
}
*current += how_many;
*remaining -= how_many;
return true;
}
// Grabs a particular type from the byte stream.
template<class T>
T ReadFromBytes(uint8_t **current, size_t *remaining)
{
PP_CHECK(ConsumeBytes(current, sizeof(T), remaining));
const T result = *(bit_cast<T *>(*current - sizeof(T)));
return result;
}
uint64_t ReadVarInt(uint8_t **current, size_t *remaining)
{
uint64_t result = 0;
bool keep_going;
int shift = 0;
do
{
const uint8_t next_number = ReadFromBytes<uint8_t>(current, remaining);
keep_going = (next_number >= 128);
result += (uint64_t)(next_number & 0x7f) << shift;
shift += 7;
} while (keep_going);
return result;
}
void ReadWireTypeAndFieldNumber(uint8_t **current, size_t *remaining, uint8_t *wire_type, uint32_t *field_number)
{
uint64_t wire_type_and_field_number = ReadVarInt(current, remaining);
*wire_type = wire_type_and_field_number & 0x07;
*field_number = wire_type_and_field_number >> 3;
}
} // namespace
std::string FieldTypeDebugString(enum FieldType type)
{
switch (type)
{
case FIELD_UNSET: return "UNSET"; break;
case FIELD_UINT32: return "UINT32"; break;
case FIELD_UINT64: return "UINT64"; break;
case FIELD_BYTES: return "BYTES"; break;
default: return "Unknown field type"; break;
}
return "Should never get here";
}
Field::Field(FieldType type, bool owns_data) : type(type), owns_data(owns_data)
{
cached_messages = nullptr;
switch (type)
{
case FIELD_UINT32:
{
value.v_uint32 = new std::vector<uint32_t>();
}
break;
case FIELD_UINT64:
{
value.v_uint64 = new std::vector<uint64_t>();
}
break;
case FIELD_BYTES:
{
value.v_bytes = new std::vector<std::pair<uint8_t *, size_t>>();
cached_messages = new std::vector<Message *>();
}
break;
default:
{
PP_LOG(ERROR) << "Bad field type when constructing field: " << type;
}
break;
}
}
Field::Field(const Field &other) : type(other.type), owns_data(other.owns_data)
{
switch (type)
{
case FIELD_UINT32:
{
value.v_uint32 = new std::vector<uint32_t>(*other.value.v_uint32);
}
break;
case FIELD_UINT64:
{
value.v_uint64 = new std::vector<uint64_t>(*other.value.v_uint64);
}
break;
case FIELD_BYTES:
{
if (owns_data)
{
value.v_bytes = new std::vector<std::pair<uint8_t *, size_t>>();
for (std::pair<uint8_t *, size_t> data_info : *other.value.v_bytes)
{
uint8_t *new_data = new uint8_t[data_info.second];
std::copy_n(data_info.first, data_info.second, new_data);
value.v_bytes->push_back({ new_data, data_info.second });
}
}
else
{
value.v_bytes = new std::vector<std::pair<uint8_t *, size_t>>(*other.value.v_bytes);
}
cached_messages = new std::vector<Message *>();
cached_messages->reserve(other.cached_messages->size());
for (Message *other_cached_message : *other.cached_messages)
{
Message *cached_message;
if (other_cached_message)
{
cached_message = new Message(*other_cached_message);
}
else
{
cached_message = nullptr;
}
cached_messages->push_back(cached_message);
}
}
break;
default:
{
PP_LOG(ERROR) << "Bad field type when constructing field: " << type;
}
break;
}
}
Field::~Field()
{
switch (type)
{
case FIELD_UINT32: delete value.v_uint32; break;
case FIELD_UINT64: delete value.v_uint64; break;
case FIELD_BYTES:
{
if (owns_data)
for (std::pair<uint8_t *, size_t> data_info : *value.v_bytes)
delete[] data_info.first;
delete value.v_bytes;
for (Message *cached_message : *cached_messages)
if (cached_message)
delete cached_message;
delete cached_messages;
break;
}
default: PP_LOG(ERROR) << "Bad field type when destroying field: " << type; break;
}
}
Message::Message() : Message(true){};
Message::Message(bool copy_arrays) : copy_arrays(copy_arrays){};
Message::Message(const Message &other) : field_map(other.field_map), fields(other.fields), copy_arrays(other.copy_arrays){};
Message::~Message(){};
bool Message::ParseFromBytes(uint8_t *bytes, size_t bytes_size)
{
uint8_t *current = bytes;
size_t remaining = bytes_size;
while (remaining > 0)
{
uint8_t wire_type;
uint32_t field_number;
ReadWireTypeAndFieldNumber(&current, &remaining, &wire_type, &field_number);
switch (wire_type)
{
case WIRETYPE_VARINT:
{
Field *field = AddField(field_number, FIELD_UINT64);
const uint64_t varint = ReadVarInt(&current, &remaining);
field->value.v_uint64->push_back(varint);
break;
}
case WIRETYPE_64BIT:
{
Field *field = AddField(field_number, FIELD_UINT64);
const uint64_t value = ReadFromBytes<uint64_t>(&current, &remaining);
field->value.v_uint64->push_back(value);
break;
}
case WIRETYPE_LENGTH_DELIMITED:
{
Field *field = AddField(field_number, FIELD_BYTES);
const uint64_t size = ReadVarInt(&current, &remaining);
uint8_t *data;
if (copy_arrays)
{
data = new uint8_t[size];
std::copy_n(current, size, data);
field->owns_data = true;
}
else
{
data = current;
field->owns_data = false;
}
field->value.v_bytes->push_back({ data, size });
field->cached_messages->push_back(nullptr);
current += size;
remaining -= size;
break;
}
case WIRETYPE_GROUP_START:
{
PP_LOG(INFO) << field_number << ": GROUPSTART" << std::endl;
PP_LOG(ERROR) << "Unhandled wire type encountered";
break;
}
case WIRETYPE_GROUP_END:
{
PP_LOG(INFO) << field_number << ": GROUPEND" << std::endl;
PP_LOG(ERROR) << "Unhandled wire type encountered";
break;
}
case WIRETYPE_32BIT:
{
Field *field = AddField(field_number, FIELD_UINT32);
const uint32_t value = ReadFromBytes<uint32_t>(&current, &remaining);
field->value.v_uint32->push_back(value);
break;
}
default:
{
PP_LOG(ERROR) << "Unknown wire type encountered: " << static_cast<int>(wire_type) << " at offset" << (bytes_size - remaining);
return false;
break;
}
}
}
return true;
}
Field *Message::AddField(int32_t number, enum FieldType type)
{
Field *field = GetField(number);
if (!field)
{
fields.push_back(Field(type, copy_arrays));
field = &fields.back();
field_map.insert({ number, fields.size() - 1 });
}
return field;
}
Field *Message::GetField(int32_t number)
{
if (field_map.count(number) == 0)
return nullptr;
return &(fields[field_map[number]]);
}
Field *Message::GetFieldAndCheckType(int32_t number, enum FieldType type)
{
Field *field = GetField(number);
PP_CHECK(field) << "No field for " << number;
PP_CHECK(field->type == type) << "For field " << number << " wanted type " << FieldTypeDebugString(type) << " but found " << FieldTypeDebugString(field->type);
return field;
}
int32_t Message::GetInt32(int32_t number)
{
Field *field = GetFieldAndCheckType(number, FIELD_UINT32);
uint32_t first_value = (*(field->value.v_uint32))[0];
int32_t zig_zag_decoded = static_cast<int32_t>((first_value >> 1) ^ (-(first_value & 1)));
return zig_zag_decoded;
}
int64_t Message::GetInt64(int32_t number)
{
Field *field = GetFieldAndCheckType(number, FIELD_UINT64);
uint64_t first_value = (*(field->value.v_uint64))[0];
int64_t zig_zag_decoded = static_cast<int64_t>((first_value >> 1) ^ (-(first_value & 1)));
return zig_zag_decoded;
}
uint32_t Message::GetUInt32(int32_t number)
{
Field *field = GetFieldAndCheckType(number, FIELD_UINT32);
uint32_t first_value = (*(field->value.v_uint32))[0];
return first_value;
}
uint64_t Message::GetUInt64(int32_t number)
{
Field *field = GetFieldAndCheckType(number, FIELD_UINT64);
uint64_t first_value = (*(field->value.v_uint64))[0];
return first_value;
}
int64_t Message::GetInt(int32_t number)
{
Field *field = GetField(number);
PP_CHECK(field) << "No field for " << number;
PP_CHECK((field->type == FIELD_UINT32) || (field->type == FIELD_UINT64))
<< "For field " << number << " wanted integer type but found " << FieldTypeDebugString(field->type);
switch (field->type)
{
case FIELD_UINT32: return GetInt32(number); break;
case FIELD_UINT64: return GetInt64(number); break;
default:
{
// Should never get here.
}
break;
}
// Should never get here.
return 0;
}
bool Message::GetBool(int32_t number)
{
return (GetInt(number) != 0);
}
float Message::GetFloat(int32_t number)
{
uint32_t int_value = GetUInt32(number);
float float_value = *(bit_cast<float *>(&int_value));
return float_value;
}
double Message::GetDouble(int32_t number)
{
uint64_t int_value = GetUInt64(number);
return *(bit_cast<double *>(&int_value));
}
std::pair<uint8_t *, size_t> Message::GetBytes(int32_t number)
{
Field *field = GetFieldAndCheckType(number, FIELD_BYTES);
std::pair<uint8_t *, size_t> first_value = (*(field->value.v_bytes))[0];
return first_value;
}
std::string Message::GetString(int32_t number)
{
Field *field = GetFieldAndCheckType(number, FIELD_BYTES);
std::pair<uint8_t *, size_t> first_value = (*(field->value.v_bytes))[0];
std::string result(first_value.first, first_value.first + first_value.second);
return result;
}
Message *Message::GetMessage(int32_t number)
{
Field *field = GetFieldAndCheckType(number, FIELD_BYTES);
Message *cached_message = field->cached_messages->at(0);
if (!cached_message)
{
std::pair<uint8_t *, size_t> first_value = (*(field->value.v_bytes))[0];
cached_message = new Message(copy_arrays);
cached_message->ParseFromBytes(first_value.first, first_value.second);
field->cached_messages->at(0) = cached_message;
}
return cached_message;
}
std::vector<int32_t> Message::GetInt32Array(int32_t number)
{
std::vector<uint64_t> raw_array = GetUInt64Array(number);
std::vector<int32_t> result;
result.reserve(raw_array.size());
for (uint64_t raw_value : raw_array)
{
int32_t zig_zag_decoded = static_cast<int32_t>((raw_value >> 1) ^ (-(raw_value & 1)));
result.push_back(zig_zag_decoded);
}
return result;
}
std::vector<int64_t> Message::GetInt64Array(int32_t number)
{
std::vector<uint64_t> raw_array = GetUInt64Array(number);
std::vector<int64_t> result;
result.reserve(raw_array.size());
for (uint64_t raw_value : raw_array)
{
int64_t zig_zag_decoded = static_cast<int64_t>((raw_value >> 1) ^ (-(raw_value & 1)));
result.push_back(zig_zag_decoded);
}
return result;
}
std::vector<uint32_t> Message::GetUInt32Array(int32_t number)
{
std::vector<uint64_t> raw_array = GetUInt64Array(number);
std::vector<uint32_t> result;
result.reserve(raw_array.size());
for (uint64_t raw_value : raw_array)
{
result.push_back(static_cast<uint32_t>(raw_value));
}
return result;
}
std::vector<uint64_t> Message::GetUInt64Array(int32_t number)
{
std::vector<uint64_t> result;
Field *field = GetField(number);
if (!field)
{
return result;
}
if (field->type == FIELD_UINT64)
{
result.reserve(field->value.v_uint64->size());
for (uint64_t value : *field->value.v_uint64)
{
result.push_back(static_cast<uint64_t>(value));
}
}
else if (field->type == FIELD_UINT32)
{
result.reserve(field->value.v_uint32->size());
for (uint32_t value : *field->value.v_uint32)
{
result.push_back(static_cast<uint64_t>(value));
}
}
else if (field->type == FIELD_BYTES)
{
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
{
uint8_t *current = data_info.first;
size_t remaining = data_info.second;
while (remaining > 0)
{
const uint64_t varint = ReadVarInt(&current, &remaining);
result.push_back(static_cast<int64_t>(varint));
}
}
}
else
{
PP_LOG(ERROR) << "Expected field type UINT32, UINT64, or BYTES but got " << FieldTypeDebugString(field->type);
}
return result;
}
std::vector<bool> Message::GetBoolArray(int32_t number)
{
std::vector<uint64_t> raw_array = GetUInt64Array(number);
std::vector<bool> result;
result.reserve(raw_array.size());
for (uint64_t raw_value : raw_array)
{
result.push_back(raw_value != 0);
}
return result;
}
std::vector<float> Message::GetFloatArray(int32_t number)
{
std::vector<float> result;
Field *field = GetField(number);
if (!field)
{
return result;
}
if (field->type == FIELD_UINT32)
{
result.reserve(field->value.v_uint32->size());
for (uint32_t value : *field->value.v_uint32)
{
result.push_back(bit_cast<float>(value));
}
}
else if (field->type == FIELD_BYTES)
{
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
{
uint8_t *current = data_info.first;
size_t remaining = data_info.second;
while (remaining > 0)
{
const uint64_t varint = ReadVarInt(&current, &remaining);
const uint32_t varint32 = static_cast<uint32_t>(varint & 0xffffffff);
result.push_back(bit_cast<float>(varint32));
}
}
}
else
{
PP_LOG(ERROR) << "Expected field type UINT32 or BYTES but got " << FieldTypeDebugString(field->type);
}
return result;
}
std::vector<double> Message::GetDoubleArray(int32_t number)
{
std::vector<double> result;
Field *field = GetField(number);
if (!field)
{
return result;
}
if (field->type == FIELD_UINT64)
{
result.reserve(field->value.v_uint64->size());
for (uint64_t value : *field->value.v_uint64)
{
result.push_back(bit_cast<double>(value));
}
}
else if (field->type == FIELD_BYTES)
{
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
{
uint8_t *current = data_info.first;
size_t remaining = data_info.second;
while (remaining > 0)
{
const uint64_t varint = ReadVarInt(&current, &remaining);
result.push_back(bit_cast<double>(varint));
}
}
}
else
{
PP_LOG(ERROR) << "Expected field type UINT64 or BYTES but got " << FieldTypeDebugString(field->type);
}
return result;
}
std::vector<std::pair<uint8_t *, size_t>> Message::GetByteArray(int32_t number)
{
std::vector<std::pair<uint8_t *, size_t>> result;
Field *field = GetField(number);
if (!field)
{
return result;
}
if (field->type == FIELD_BYTES)
{
result.reserve(field->value.v_bytes->size());
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
{
result.push_back(data_info);
}
}
else
{
PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type);
}
return result;
}
std::vector<std::string> Message::GetStringArray(int32_t number)
{
std::vector<std::string> result;
Field *field = GetField(number);
if (!field)
return result;
if (field->type == FIELD_BYTES)
{
result.reserve(field->value.v_bytes->size());
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
{
result.push_back(std::string(data_info.first, data_info.first + data_info.second));
}
}
else
{
PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type);
}
return result;
}
std::vector<Message *> Message::GetMessageArray(int32_t number)
{
std::vector<Message *> result;
Field *field = GetField(number);
if (!field)
return result;
if (field->type == FIELD_BYTES)
{
result.reserve(field->value.v_bytes->size());
for (size_t i = 0; i < field->value.v_bytes->size(); ++i)
{
Message *cached_message = field->cached_messages->at(i);
if (!cached_message)
{
std::pair<uint8_t *, size_t> value = field->value.v_bytes->at(i);
cached_message = new Message(copy_arrays);
cached_message->ParseFromBytes(value.first, value.second);
field->cached_messages->at(i) = cached_message;
}
result.push_back(cached_message);
}
}
else
{
PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type);
}
return result;
}
} // namespace picoproto

View File

@@ -0,0 +1,213 @@
/* Copyright 2016 Pete Warden. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
/*
See the README for full details, but this module lets you read in protobuf
encoded files with a minimal code footprint.
It doesn't create classes for each kind of message it encounters, it just has a
single Message interface that lets you access the members of the protobuf as a
key/value store. This loses a lot of the convenience of type-checked classes,
but it does mean that very little code is needed to access data from files.
As a simple example, if you had read a `bytes_size` long file into `bytes` that
contained a TensorFlow GraphDef proto:
Message graph_def;
graph_def.ParseFromBytes(bytes, bytes_size);
You can then access the different fields of the GraphDef using the field
numbers assigned in the .proto file:
std::vector<picoproto::Message*> nodes = graph_def.GetMessageArray(1);
One big difference between this minimal approach and normal protobufs is that
the calling code has to already know the field number and type of any members
it's trying to access. Here I know that the `node` field is number 1, and that
it should contain a repeated list of NodeDefs. Since they are not primitive
types like numbers or strings, they are accessed as an array of Messages.
Here are the design goals of this module:
- Keep the code size tiny (single-digit kilobytes on most platforms).
- Minimize memory usage (for example allow in-place references to byte data).
- Provide a simple, readable implementation that can be ported easily.
- Deserialize all saved protobuf files into a usable representation.
- No dependencies other than the standard C++ library.
- No build-time support (e.g. protoc) required.
Here's what it's explicitly not offering:
- Providing a readable and transparent way of accessing serialized data.
- Saving out data to protobuf format.
*/
#ifndef INCLUDE_PICOPROTO_H
#define INCLUDE_PICOPROTO_H
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <map>
#include <string>
#include <vector>
// To keep dependencies minimal, some bare-bones macros to make logging easier.
#define PP_LOG(X) PP_LOG_##X
#define PP_LOG_INFO std::cerr << __FILE__ << ":" << __LINE__ << " - INFO: "
#define PP_LOG_WARN std::cerr << __FILE__ << ":" << __LINE__ << " - WARN: "
#define PP_LOG_ERROR std::cerr << __FILE__ << ":" << __LINE__ << " - ERROR: "
#define PP_CHECK(X) \
if (!(X)) \
PP_LOG(ERROR) << "PP_CHECK(" << #X << ") failed. "
namespace picoproto
{
// These roughly correspond to the wire types used to save data in protobuf
// files. The best reference to understand the full format is:
// https://developers.google.com/protocol-buffers/docs/encoding
// Because we don't know the bit-depth of VarInts, they're always stored as
// uint64 values, which is why there's no specific type for them.
enum FieldType
{
FIELD_UNSET,
FIELD_UINT32,
FIELD_UINT64,
FIELD_BYTES,
};
// Gives a readable name for the field type for logging purposes.
std::string FieldTypeDebugString(enum FieldType type);
// Forward declare the main message class, since fields can contain them.
class Message;
// Fields are the building blocks of messages. They contain the values for each
// data member, and handle all the allocation and deallocation of storage.
// It's unlikely you'll want to access this class directly, since you'll
// normally want to use Message below to pull typed values.
class Field
{
public:
// You need to specify the type of a Field on creation, so that the right
// storage can be set up for the values. You also need to indicate whether the
// underlying memory will be around for the lifetime of the message (in which
// case no copies are needed) or whether the class should make copies and take
// ownership in case the data goes away.
Field(FieldType type, bool owns_data);
Field(const Field &other);
~Field();
enum FieldType type;
// I know, this isn't very OOP, but the simplicity of keeping track of a type
// and deciding how to initialize and access the data based on that persuaded
// me this was the best approach. The `value` member contains whatever data
// the field should be holding.
union
{
std::vector<uint32_t> *v_uint32;
std::vector<uint64_t> *v_uint64;
std::vector<std::pair<uint8_t *, size_t>> *v_bytes;
} value;
// One of the drawbacks of not requiring .proto files ahead of time is that I
// don't know if a length-delimited field contains raw bytes, strings, or
// sub-messages. The only time we know that a field should be interpreted as a
// message is when client code requests it in that form. Because parsing can
// be costly, here we cache the results of any such calls for subsequent
// accesses.
std::vector<Message *> *cached_messages;
// If this is set, then the object will allocate its own storage for
// length-delimited values, and copy from the input stream. If you know the
// underlying data will be around for the lifetime of the message, you can
// save memory and copies by leaving this as false.
bool owns_data;
};
// The main interface for loading and accessing serialized protobuf data.
class Message
{
public:
// If you're not sure about the lifetime of any binary data you're reading
// from, just call this default constructor.
Message();
// In the case when you're sure the lifetime of the byte stream you'll be
// decoding is longer than the lifetime of the message, you can set
// copy_arrays to false. This is especially useful if you have a memory
// mapped file to read from containing large binary blobs, since you'll skip
// a lot of copying and extra allocation.
Message(bool copy_arrays);
Message(const Message &other);
~Message();
// Populates fields with all of the data from this stream of bytes.
// You can call this repeatedly with new messages, and the results will be
// merged together.
bool ParseFromBytes(uint8_t *binary, size_t binary_size);
// These are the accessor functions if you're expecting exactly one value in a
// field. As discussed above, the burden is on the client code to know the
// field number and type of each member it's trying to access, and so pick the
// correct accessor function.
// If the field isn't present, this will raise an error, so if it's optional
// you should use the array accessors below.
int32_t GetInt32(int32_t number);
int64_t GetInt64(int32_t number);
uint32_t GetUInt32(int32_t number);
uint64_t GetUInt64(int32_t number);
int64_t GetInt(int32_t number);
bool GetBool(int32_t number);
float GetFloat(int32_t number);
double GetDouble(int32_t number);
std::pair<uint8_t *, size_t> GetBytes(int32_t number);
std::string GetString(int32_t number);
Message *GetMessage(int32_t number);
// If you're not sure if a value will be present, or if it is repeated, you
// should call these array functions. If no such field has been seen, then the
// result will be an empty vector, otherwise you'll get back one or more
// entries.
std::vector<int32_t> GetInt32Array(int32_t number);
std::vector<int64_t> GetInt64Array(int32_t number);
std::vector<uint32_t> GetUInt32Array(int32_t number);
std::vector<uint64_t> GetUInt64Array(int32_t number);
std::vector<bool> GetBoolArray(int32_t number);
std::vector<float> GetFloatArray(int32_t number);
std::vector<double> GetDoubleArray(int32_t number);
std::vector<std::pair<uint8_t *, size_t>> GetByteArray(int32_t number);
std::vector<std::string> GetStringArray(int32_t number);
std::vector<Message *> GetMessageArray(int32_t number);
// It's unlikely you'll want to access fields directly, but here's an escape
// hatch in case you do have to manipulate them more directly.
Field *GetField(int32_t number);
private:
// Inserts a new field, updating all the internal data structures.
Field *AddField(int32_t number, enum FieldType type);
Field *GetFieldAndCheckType(int32_t number, enum FieldType type);
// Maps from a field number to an index in the `fields` vector.
std::map<int32_t, size_t> field_map;
// The core list of fields that have been parsed.
std::vector<Field> fields;
bool copy_arrays;
};
} // namespace picoproto
#endif // INCLUDE_PICOPROTO_H

View File

@@ -1,4 +1,4 @@
#include "qv2ray/utils/HTTPRequestHelper.hpp"
#include "qv2ray/v2/utils/HTTPRequestHelper.hpp"
#include "db/Database.hpp"
#include "db/ProfileFilter.hpp"

View File

@@ -192,7 +192,7 @@
</message>
<message>
<source>Copy profile share links</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Copied</source>
@@ -200,7 +200,7 @@
</message>
<message>
<source>Copy profile share links (Nekoray)</source>
<translation> (Nekoray)</translation>
<translation> (Nekoray)</translation>
</message>
</context>
<context>
@@ -293,7 +293,7 @@
<context>
<name>DialogHotkey</name>
<message>
<source>Hot key</source>
<source>Hotkey</source>
<translation></translation>
</message>
<message>
@@ -745,8 +745,8 @@
<translation></translation>
</message>
<message>
<source>Routes</source>
<translation></translation>
<source>Routing VPN Settings</source>
<translation> VPN </translation>
</message>
<message>
<source>Add profile from clipboard</source>
@@ -924,7 +924,7 @@ End: %2</source>
</message>
<message>
<source>Remove Unavailable</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Settings</source>
@@ -959,8 +959,8 @@ End: %2</source>
<translation> [ Delete ]</translation>
</message>
<message>
<source>Hot key</source>
<translation></translation>
<source>Hotkey Settings</source>
<translation></translation>
</message>
<message>
<source>QR Code and link</source>
@@ -987,12 +987,12 @@ End: %2</source>
<translation>: %1</translation>
</message>
<message>
<source>Copy links of selected</source>
<translation></translation>
<source>Copy links of selected [ Ctrl+C ]</source>
<translation> [ Ctrl+C ]</translation>
</message>
<message>
<source>Copied %1 item(s)</source>
<translation>%1 </translation>
<translation> %1 </translation>
</message>
<message>
<source>New profile from clipboard</source>
@@ -1012,7 +1012,7 @@ End: %2</source>
</message>
<message>
<source>Delete Repeat</source>
<translation></translation>
<translation></translation>
</message>
<message>
<source>Select All</source>

View File

@@ -1,7 +1,7 @@
#include "dialog_basic_settings.h"
#include "ui_dialog_basic_settings.h"
#include "qv2ray/ui/widgets/editors/w_JsonEditor.hpp"
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
#include "ui/ThemeManager.hpp"
#include "main/GuiUtils.hpp"
#include "main/NekoRay.hpp"

View File

@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Hot key</string>
<string>Hotkey</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">

View File

@@ -1,7 +1,8 @@
#include "dialog_manage_routes.h"
#include "ui_dialog_manage_routes.h"
#include "qv2ray/ui/widgets/editors/w_JsonEditor.hpp"
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
#include "qv2ray/v3/components/GeositeReader/GeositeReader.hpp"
#include "main/GuiUtils.hpp"
#include <QFile>
@@ -59,14 +60,23 @@ DialogManageRoutes::DialogManageRoutes(QWidget *parent) :
builtInSchemesMenu->addActions(this->getBuiltInSchemes());
ui->preset->setMenu(builtInSchemesMenu);
QString geoipFn = QApplication::applicationDirPath() + "/geoip.dat";
QString geositeFn = QApplication::applicationDirPath() + +"/geosite.dat";
if (!NekoRay::dataStore->v2ray_asset_dir.isEmpty()) {
geoipFn = NekoRay::dataStore->v2ray_asset_dir + "/geoip.dat";
geositeFn = NekoRay::dataStore->v2ray_asset_dir + "/geosite.dat";
}
//
directDomainTxt = new AutoCompleteTextEdit("geosite", {}, this);
proxyDomainTxt = new AutoCompleteTextEdit("geosite", {}, this);
blockDomainTxt = new AutoCompleteTextEdit("geosite", {}, this);
const auto sourceStringsDomain = Qv2ray::components::GeositeReader::ReadGeoSiteFromFile(geoipFn);
directDomainTxt = new AutoCompleteTextEdit("geosite", sourceStringsDomain, this);
proxyDomainTxt = new AutoCompleteTextEdit("geosite", sourceStringsDomain, this);
blockDomainTxt = new AutoCompleteTextEdit("geosite", sourceStringsDomain, this);
//
directIPTxt = new AutoCompleteTextEdit("geoip", {}, this);
proxyIPTxt = new AutoCompleteTextEdit("geoip", {}, this);
blockIPTxt = new AutoCompleteTextEdit("geoip", {}, this);
const auto sourceStringsIP = Qv2ray::components::GeositeReader::ReadGeoSiteFromFile(geositeFn);
qDebug() << sourceStringsIP;
directIPTxt = new AutoCompleteTextEdit("geoip", sourceStringsIP, this);
proxyIPTxt = new AutoCompleteTextEdit("geoip", sourceStringsIP, this);
blockIPTxt = new AutoCompleteTextEdit("geoip", sourceStringsIP, this);
//
ui->directTxtLayout->addWidget(directDomainTxt, 0, 0);
ui->proxyTxtLayout->addWidget(proxyDomainTxt, 0, 0);

View File

@@ -3,7 +3,7 @@
#include <QDialog>
#include <QMenu>
#include "qv2ray/ui/QvAutoCompleteTextEdit.hpp"
#include "qv2ray/v2/ui/QvAutoCompleteTextEdit.hpp"
#include "main/NekoRay.hpp"
QT_BEGIN_NAMESPACE

View File

@@ -119,7 +119,7 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="copy_links">
<property name="text">

View File

@@ -10,7 +10,8 @@
#include "ui/edit/edit_custom.h"
#include "fmt/includes.h"
#include "qv2ray/ui/widgets/editors/w_JsonEditor.hpp"
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
#include "main/GuiUtils.hpp"
#include <QInputDialog>

View File

@@ -1,7 +1,7 @@
#include "edit_custom.h"
#include "ui_edit_custom.h"
#include "qv2ray/ui/widgets/editors/w_JsonEditor.hpp"
#include "qv2ray/v2/ui/widgets/editors/w_JsonEditor.hpp"
#include "fmt/CustomBean.hpp"
EditCustom::EditCustom(QWidget *parent) :

View File

@@ -16,12 +16,12 @@
#include "3rdparty/qrcodegen.hpp"
#include "3rdparty/VT100Parser.hpp"
#include "qv2ray/ui/LogHighlighter.hpp"
#include "qv2ray/v2/ui/LogHighlighter.hpp"
#ifndef NKR_NO_EXTERNAL
#include "3rdparty/ZxingQtReader.hpp"
#include "qv2ray/components/proxy/QvProxyConfigurator.hpp"
#include "qv2ray/v2/components/proxy/QvProxyConfigurator.hpp"
#endif
@@ -254,6 +254,7 @@ MainWindow::MainWindow(QWidget *parent)
//
ui->menu_program_preference->addActions(ui->menu_preferences->actions());
connect(ui->menu_add_from_clipboard2, &QAction::triggered, ui->menu_add_from_clipboard, &QAction::trigger);
connect(shortcut_ctrl_c, &QShortcut::activated, ui->menu_copy_links, &QAction::trigger);
connect(shortcut_ctrl_v, &QShortcut::activated, ui->menu_add_from_clipboard, &QAction::trigger);
//
connect(ui->menu_program, &QMenu::aboutToShow, this, [=]() {
@@ -938,6 +939,7 @@ void MainWindow::on_menu_copy_links_triggered() {
for (const auto &ent: ents) {
links += ent->bean->ToShareLink();
}
if (links.length() == 0) return;
QApplication::clipboard()->setText(links.join("\n"));
MessageBoxInfo("NekoRay", tr("Copied %1 item(s)").arg(links.length()));
}

View File

@@ -110,6 +110,7 @@ private:
Ui::MainWindow *ui;
QSystemTrayIcon *tray;
QShortcut *shortcut_ctrl_f = new QShortcut(QKeySequence("Ctrl+F"), this);
QShortcut *shortcut_ctrl_c = new QShortcut(QKeySequence("Ctrl+C"), this);
QShortcut *shortcut_ctrl_v = new QShortcut(QKeySequence("Ctrl+V"), this);
QShortcut *shortcut_esc = new QShortcut(QKeySequence("Esc"), this);
//

View File

@@ -498,8 +498,8 @@
<property name="title">
<string>Preferences</string>
</property>
<addaction name="menu_basic_settings"/>
<addaction name="menu_manage_groups"/>
<addaction name="menu_basic_settings"/>
<addaction name="menu_routing_settings"/>
<addaction name="menu_hotkey_settings"/>
</widget>
@@ -582,7 +582,7 @@
</action>
<action name="menu_routing_settings">
<property name="text">
<string>Routes</string>
<string>Routing VPN Settings</string>
</property>
</action>
<action name="menu_add_from_clipboard">
@@ -715,7 +715,7 @@
</action>
<action name="menu_hotkey_settings">
<property name="text">
<string>Hot key</string>
<string>Hotkey Settings</string>
</property>
</action>
<action name="menu_select_all">
@@ -746,7 +746,7 @@
</action>
<action name="menu_copy_links">
<property name="text">
<string>Copy links of selected</string>
<string>Copy links of selected [ Ctrl+C ]</string>
</property>
</action>
<action name="menu_spmode_vpn">