Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 fix Kai client's build spec for Windows #351

Merged
merged 1 commit into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions playpen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ The goals of this effort are:
As of writing this, here's the progress we made on the goals above:

- We have a JSON-RPC interface in front of the Client CLI. The JSON-RPC interface can be found in [./client/rpc.py](./client/rpc.py). It exposes `get_incident_solutions_for_file` function that generates a fix for one file. There are two example clients (Python and Javascript) we have written that talk with the interface over I/O streams.

- We have a `build.spec` file that builds the JSON-RPC client into a binary using PyInstaller.

### Building JSON-RPC interface into a binary
Expand All @@ -36,6 +37,12 @@ pyinstaller build.spec

Once successful, a binary will be generated at `./dist/cli`.

#### Building for different platforms

We are using PyInstaller to create binaries. To create a binary for a certain platform / arch, we are building on the same platform + arch. As per our understanding, it is possible to potentially cross-compile for different architectures but not the platform itself.

So far, we have successfully built and tested binaries for MacOS and Windows (built on respective machines).

### Testing JSON-RPC binary

Now that we have built our JSON-RPC interface into a binary, we will test it using a Python and a JS client that communicates. Both of these clients use a hardcoded path `./dist/cli` to run the JSON-RPC server. Make sure you have built the binary before moving forward.
Expand Down
2 changes: 1 addition & 1 deletion playpen/build.spec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ script_path = 'client/rpc.py'

a = Analysis(
[script_path],
pathex=[os.path.dirname(script_path)],
pathex=[os.path.dirname(script_path), '../'],
binaries=[],
datas=data_dirs,
hiddenimports=["_ssl"],
Expand Down
25 changes: 15 additions & 10 deletions playpen/client/rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

"""This module is intended to facilitate using Konveyor with LLMs."""


import json
import logging
import os
Expand Down Expand Up @@ -49,7 +50,6 @@ def run(self):

if method:
if rpc_id is not None:
# a call for method
if method not in self.method_callbacks:
raise ResponseError(
ErrorCodes.MethodNotFound,
Expand All @@ -70,6 +70,10 @@ def run(self):
self.handle_result(rpc_id, result, error)
except ResponseError as e:
self.send_response(rpc_id, None, e)
except Exception as e:
self.send_response(
rpc_id, None, ResponseError(ErrorCodes.InternalError, str(e))
)


class CustomRpcEndpoint(JsonRpcEndpoint):
Expand All @@ -81,16 +85,16 @@ def __add_header(self, json_string: str):
def send_request(self, message):
json_string = json.dumps(message, cls=MyEncoder)
jsonrpc_req = self.__add_header(json_string)
log.debug(f"Sending data over stdin {jsonrpc_req}")
log.debug(f"sending data over stdin {repr(jsonrpc_req)}")
with self.write_lock:
self.stdin.write(jsonrpc_req)
self.stdin.buffer.write(jsonrpc_req.encode())
self.stdin.flush()

def recv_response(self):
with self.read_lock:
message_size = None
while True:
line = self.stdout.readline()
line = self.stdout.buffer.readline().decode("utf-8")
if not line:
return None
if not line.endswith("\r\n") and not line.endswith("\n"):
Expand All @@ -116,8 +120,8 @@ def recv_response(self):
if not message_size:
raise ResponseError(ErrorCodes.ParseError, "Bad header: missing size")

jsonrpc_res = self.stdout.read(message_size)
log.debug(f"Read data from stdout {jsonrpc_res}")
jsonrpc_res = self.stdout.buffer.read(message_size).decode("utf-8")
log.debug(f"read data from stdout {repr(jsonrpc_res)}")
return json.loads(jsonrpc_res)


Expand Down Expand Up @@ -206,7 +210,7 @@ def _validate_path(self, path: str, dir: bool = False) -> bool:
class KaiClientRPCServer:
def get_incident_solutions_for_file(self, **kwargs) -> str:
rpc_params = RPCParams(**kwargs)
log.debug(f"got rpc params {rpc_params}")
log.debug(f"got rpc params {rpc_params._data}")
config = get_config(rpc_params.config_path)

setup_file_handler(
Expand Down Expand Up @@ -270,16 +274,17 @@ def get_incident_solutions_for_file(self, **kwargs) -> str:
return result.updated_file
except Exception as e:
trace.exception(-1, -1, e, traceback.format_exc())
log.debug(f"error processing file: {e}")
log.debug(f"failed to generate fix: {e}")
raise ResponseError(
ErrorCodes.InternalError, f"failed to generate fix - {str(e)}"
) from e
finally:
end = time.time()
trace.end(end)
log.info(
f"END - completed in '{end-start}s: - App: '{rpc_params.app_name}', File: '{rpc_params.input_file_path}' with {len(incidents)} incidents'"
)

raise ResponseError("failed to generate fix")


def run_rpc_server():
# filter warnings so stdout is not polluted
Expand Down
3 changes: 3 additions & 0 deletions playpen/rpc-client.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ def main():
)
print(response)
print("\nReceived response successfully!")
except Exception as e:
print(str(e))
print("\nFailed to generate fix")
finally:
rpc_server.stdin.close()
rpc_server.stdout.close()
Expand Down
Loading