Skip to content

Commit 662af17

Browse files
author
kezhengjie
committed
Update
* remember last window positions; * get remote info of files in directory * update rpc_service.py
1 parent ea20bf3 commit 662af17

File tree

5 files changed

+156
-50
lines changed

5 files changed

+156
-50
lines changed

.vscode/launch.json

+8-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@
55
"version": "0.2.0",
66
"configurations": [
77
{
8-
"name": "Python 调试程序: 当前文件",
8+
"name": "mainwindow",
99
"type": "debugpy",
1010
"request": "launch",
1111
"program": "${workspaceFolder}/mainwindow.py",
1212
"console": "integratedTerminal"
13+
},
14+
{
15+
"name": "Python 调试程序: 当前文件",
16+
"type": "debugpy",
17+
"request": "launch",
18+
"program": "${file}",
19+
"console": "integratedTerminal"
1320
}
1421
]
1522
}

config.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,34 @@
11
import json
22

3+
from rpc_service import DEFAULT_GRPC_PORT
4+
35

46
class Config:
57
def __init__(self) -> None:
68
self.ip = ""
79
self.filepath = ""
10+
self.listen_port = DEFAULT_GRPC_PORT
11+
self.x = None
12+
self.y = None
813

914
try:
1015
with open("config.json") as fd:
1116
d = json.loads(fd.read())
1217
self.ip = d["ip"]
1318
self.filepath = d["filepath"]
19+
try:
20+
self.listen_port = int(d["listen_port"])
21+
except Exception as e:
22+
print(e)
23+
try:
24+
self.x = int(d["x"])
25+
except Exception as e:
26+
print(e)
27+
try:
28+
self.y = int(d["y"])
29+
except Exception as e:
30+
print(e)
31+
1432
except Exception as e:
1533
print(e)
1634

@@ -22,6 +40,9 @@ def save(self):
2240
{
2341
"ip": self.ip,
2442
"filepath": self.filepath,
43+
"listen_port": self.listen_port,
44+
"x": self.x,
45+
"y": self.y,
2546
}
2647
)
2748
)

mainwindow.py

+49-5
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@
1818
)
1919
from PySide6.QtCore import QObject, Signal
2020
import grpc
21+
from PySide6.QtGui import QMoveEvent
2122

2223
from compress import compress_file, decompress
23-
from rpc_service import GRPC_PORT, GrpcClient, RPCService
24+
from rpc_service import GrpcClient, RPCService
2425
from config import Config
2526
import rpc_service_pb2_grpc
2627

@@ -45,7 +46,7 @@ def initUI(self):
4546
self.config = Config()
4647

4748
hbox_layout_01 = QHBoxLayout()
48-
self.ip_label = QLabel("ip:")
49+
self.ip_label = QLabel("远程地址:")
4950
self.ip_label.setMinimumWidth(35)
5051
self.ip_edit = QLineEdit(self.config.ip)
5152
# self.ip_edit.setStyleSheet("QLineEdit { padding-left: 0px; margin-left:14px}")
@@ -59,14 +60,17 @@ def initUI(self):
5960
qvbox_layout.addLayout(hbox_layout_01)
6061

6162
hbox_layout_02 = QHBoxLayout()
62-
self.filepath_title_label = QLabel("文件:")
63+
self.filepath_title_label = QLabel("目标:")
6364
self.filepath_title_label.setMinimumWidth(35)
6465
self.filepath_line_edit = QLineEdit(self.config.filepath)
6566
self.select_file_button = QPushButton("选择文件")
6667
self.select_file_button.clicked.connect(self.show_file_select_dialog)
68+
self.select_directory_button = QPushButton("选择文件夹")
69+
self.select_directory_button.clicked.connect(self.show_directory_select_dialog)
6770
hbox_layout_02.addWidget(self.filepath_title_label, 0)
6871
hbox_layout_02.addWidget(self.filepath_line_edit, 1)
6972
hbox_layout_02.addWidget(self.select_file_button, 0)
73+
hbox_layout_02.addWidget(self.select_directory_button, 0)
7074
qvbox_layout.addLayout(hbox_layout_02)
7175

7276
self.console = QTextEdit()
@@ -90,32 +94,62 @@ def initUI(self):
9094
self.setLayout(qvbox_layout)
9195
self.setGeometry(300, 300, 500, 400)
9296
self.setWindowTitle("Game Save Sync")
97+
if self.config.x is not None and self.config.y is not None:
98+
self.move(self.config.x, self.config.y)
9399
self.show()
94100
self.start_grpc_thread()
95101

102+
def moveEvent(self, ev: QMoveEvent):
103+
self.config.x = ev.pos().x()
104+
self.config.y = ev.pos().y()
105+
self.config.save()
106+
96107
def start_grpc_thread(self):
97108
self.grpc_server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
98109
rpc_service_pb2_grpc.add_RpcServicer_to_server(
99110
RPCService(get_filepath=self.filepath_line_edit.text, logger=self.print),
100111
self.grpc_server,
101112
)
102-
self.grpc_server.add_insecure_port("[::]:" + str(GRPC_PORT))
113+
self.grpc_server.add_insecure_port("[::]:" + str(self.config.listen_port))
103114
self.grpc_server.start()
104115

105116
def show_file_select_dialog(self):
106117
filepath = QFileDialog.getOpenFileName(
107118
self,
108119
"选择文件",
120+
(
121+
os.path.dirname(self.filepath_line_edit.text())
122+
if self.filepath_line_edit.text() != ""
123+
else "."
124+
),
109125
)
110126
if filepath[0] != "":
111127
self.filepath_line_edit.setText(filepath[0])
112128
self.config.filepath = filepath[0]
113129
self.config.save()
114130

131+
def show_directory_select_dialog(self):
132+
dir_path = QFileDialog.getExistingDirectory(
133+
self,
134+
"选择文件夹",
135+
(
136+
os.path.dirname(self.filepath_line_edit.text())
137+
if self.filepath_line_edit.text() != ""
138+
else "."
139+
),
140+
)
141+
if dir_path != "":
142+
self.filepath_line_edit.setText(dir_path)
143+
self.config.filepath = dir_path
144+
self.config.save()
145+
115146
def show_ip_edit_dialog(self):
116147
input_dialog = QInputDialog()
117148
text, ok = input_dialog.getText(
118-
self, "修改ip", "请输入ip:", text=self.config.ip
149+
self,
150+
"修改地址",
151+
"请输入地址:",
152+
text=self.config.ip,
119153
)
120154
if ok:
121155
self.ip_edit.setText(text)
@@ -129,13 +163,23 @@ def compress_file(self, filepath: str):
129163
self.print(f"压缩完成")
130164
return zip_filepath
131165

166+
def sync_directory(self):
167+
with GrpcClient.get_channel(self.config.ip) as channel:
168+
response = GrpcClient.get_remote_files_status(
169+
channel, os.path.basename(self.filepath_line_edit.text())
170+
)
171+
for file_info in response.files:
172+
self.print(str(file_info))
173+
132174
def start_sync(self):
133175
self.sync_button.setDisabled(True)
134176

135177
def sync_method():
136178
self.print("开始同步")
137179
try:
138180
local_filepath = self.filepath_line_edit.text()
181+
if os.path.isdir(local_filepath):
182+
return self.sync_directory()
139183
local_file_md5 = ""
140184
local_file_basename = os.path.basename(local_filepath)
141185
local_file_mtime = 0

rpc_service.proto

+29-40
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,36 @@ syntax = "proto3";
22

33
package game.save.sync;
44

5-
service Rpc {
6-
rpc Ping (PingRequest) returns (PingReply) {}
7-
rpc Binary(BinaryRequest) returns(BinaryReply){}
8-
rpc FileStatus(FileStatusRequest) returns(FileStatusReply){}
9-
rpc UploadFile(stream UploadFileRequest)returns(UploadFileReply){}
10-
rpc DownloadFile(DownloadFileRequest)returns(stream DownloadFileReply){}
11-
}
12-
13-
message DownloadFileRequest{}
14-
message DownloadFileReply{
15-
bytes data = 1;
16-
}
17-
18-
message UploadFileRequest{
19-
bytes data = 1;
20-
}
21-
22-
message UploadFileReply{
23-
bool status = 1;
24-
}
25-
26-
message PingRequest {
27-
string msg = 1;
28-
}
29-
30-
message PingReply {
31-
string msg = 1;
32-
}
33-
34-
message BinaryRequest{
35-
bytes b = 1;
36-
}
37-
38-
message BinaryReply{
39-
string msg = 1;
40-
}
41-
42-
message FileStatusRequest{}
43-
message FileStatusReply{
5+
service Rpc {
6+
rpc Ping(PingRequest) returns (PingReply) {}
7+
rpc Binary(BinaryRequest) returns (BinaryReply) {}
8+
rpc FileStatus(FileStatusRequest) returns (FileStatusReply) {}
9+
rpc UploadFile(stream UploadFileRequest) returns (UploadFileReply) {}
10+
rpc DownloadFile(DownloadFileRequest) returns (stream DownloadFileReply) {}
11+
rpc DirectoryStatus(DirectoryStatusRequest) returns (DirectoryStatusReply) {}
12+
rpc ReceiveDirectory(ReceiveDirectoryRequest)
13+
returns (ReceiveDirectoryReply) {}
14+
rpc DownloadDirectory(DownloadDirectoryRequest)
15+
returns (DownloadDirectoryReply) {}
16+
}
17+
18+
message ReceiveDirectoryRequest {}
19+
message ReceiveDirectoryReply {}
20+
message DownloadDirectoryRequest {}
21+
message DownloadDirectoryReply {}
22+
message DirectoryStatusRequest { string directory_name = 1; }
23+
message DirectoryStatusReply { repeated FileStatusReply files = 1; }
24+
message DownloadFileRequest {}
25+
message DownloadFileReply { bytes data = 1; }
26+
message UploadFileRequest { bytes data = 1; }
27+
message UploadFileReply { bool status = 1; }
28+
message PingRequest { string msg = 1; }
29+
message PingReply { string msg = 1; }
30+
message BinaryRequest { bytes b = 1; }
31+
message BinaryReply { string msg = 1; }
32+
message FileStatusRequest {}
33+
message FileStatusReply {
4434
string md5 = 1;
4535
int64 timestamp = 2;
4636
string filename = 3;
4737
}
48-

rpc_service.py

+49-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import rpc_service_pb2_grpc
1212
from threading import Thread
1313

14-
GRPC_PORT = 6465
14+
DEFAULT_GRPC_PORT = 6465
1515

1616

1717
class RPCService(rpc_service_pb2_grpc.RpcServicer):
@@ -34,6 +34,9 @@ def FileStatus(self, request, context):
3434
return rpc_service_pb2.FileStatusReply(
3535
md5="", timestamp=0, filename=os.path.basename(filepath)
3636
)
37+
if os.path.isdir(filepath):
38+
context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
39+
context.set_details("not a file")
3740
file_timestamp = int(os.path.getmtime(filepath))
3841
with open(filepath, "rb") as fp:
3942
data = fp.read()
@@ -70,14 +73,49 @@ def DownloadFile(self, request, context):
7073
return
7174
yield rpc_service_pb2.DownloadFileReply(data=data)
7275

76+
def DirectoryStatus(self, request, context):
77+
directory_path = self._get_filepath()
78+
if os.path.basename(directory_path) != request.directory_name:
79+
context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
80+
context.set_details("not a directory")
81+
return rpc_service_pb2.DirectoryStatusReply()
82+
result = []
83+
for path, _, filenames in os.walk(directory_path):
84+
for filename in filenames:
85+
local_filepath = os.path.join(path, filename)
86+
relative_path = local_filepath[len(directory_path) + 1 :]
87+
md5 = None
88+
try:
89+
with open(local_filepath, "rb") as fp:
90+
data = fp.read()
91+
md5 = hashlib.md5(data).hexdigest()
92+
file_timestamp = int(os.path.getmtime(local_filepath))
93+
except Exception as e:
94+
print(e)
95+
continue
96+
result.append(
97+
rpc_service_pb2.FileStatusReply(
98+
md5=md5,
99+
timestamp=file_timestamp,
100+
filename=relative_path,
101+
)
102+
)
103+
return rpc_service_pb2.DirectoryStatusReply(files=result)
104+
73105

74106
BUF_SIZE = 1024 * 1024 * 2
75107

76108

77109
class GrpcClient:
78110
@staticmethod
79-
def get_channel(ip: str):
80-
return grpc.insecure_channel(f"{ip}:{GRPC_PORT}")
111+
def get_channel(addr: str):
112+
ip = None
113+
port = DEFAULT_GRPC_PORT
114+
i = addr.find(":")
115+
if i != -1:
116+
ip = addr[:i]
117+
port = int(addr[i + 1 :])
118+
return grpc.insecure_channel(f"{ip}:{port}")
81119

82120
@staticmethod
83121
def get_remote_file_status(channel: grpc.Channel):
@@ -103,6 +141,13 @@ def download_file(channel: grpc.Channel):
103141
stub = rpc_service_pb2_grpc.RpcStub(channel)
104142
return stub.DownloadFile(rpc_service_pb2.DownloadFileRequest())
105143

144+
@staticmethod
145+
def get_remote_files_status(channel: grpc.Channel, directory_name: str):
146+
stub = rpc_service_pb2_grpc.RpcStub(channel)
147+
return stub.DirectoryStatus(
148+
rpc_service_pb2.DirectoryStatusRequest(directory_name=directory_name)
149+
)
150+
106151

107152
def serve():
108153
def wrapper():
@@ -140,7 +185,7 @@ def test():
140185
RPCService(get_filepath=lambda: sys.argv[1], logger=print),
141186
grpc_server,
142187
)
143-
grpc_server.add_insecure_port("[::]:" + str(GRPC_PORT))
188+
grpc_server.add_insecure_port("[::]:" + str(DEFAULT_GRPC_PORT))
144189
grpc_server.start()
145190
try:
146191
while True:

0 commit comments

Comments
 (0)