mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-29 17:47:14 +02:00
Thread safe internal PIO Core calling for PIO Home
This commit is contained in:
@ -16,7 +16,8 @@ from __future__ import absolute_import
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import thread
|
||||
from io import BytesIO
|
||||
|
||||
import jsonrpc # pylint: disable=import-error
|
||||
@ -26,8 +27,46 @@ from platformio import __main__, __version__, util
|
||||
from platformio.compat import string_types
|
||||
|
||||
|
||||
class ThreadSafeStdBuffer(object):
|
||||
|
||||
def __init__(self, parent_stream, parent_thread_id):
|
||||
self.parent_stream = parent_stream
|
||||
self.parent_thread_id = parent_thread_id
|
||||
self._buffer = {}
|
||||
|
||||
def write(self, value):
|
||||
thread_id = thread.get_ident()
|
||||
if thread_id == self.parent_thread_id:
|
||||
return self.parent_stream.write(value)
|
||||
if thread_id not in self._buffer:
|
||||
self._buffer[thread_id] = BytesIO()
|
||||
return self._buffer[thread_id].write(value)
|
||||
|
||||
def flush(self):
|
||||
return (self.parent_stream.flush()
|
||||
if thread.get_ident() == self.parent_thread_id else None)
|
||||
|
||||
def getvalue_and_close(self, thread_id=None):
|
||||
thread_id = thread_id or thread.get_ident()
|
||||
if thread_id not in self._buffer:
|
||||
return ""
|
||||
result = self._buffer.get(thread_id).getvalue()
|
||||
self._buffer.get(thread_id).close()
|
||||
del self._buffer[thread_id]
|
||||
return result
|
||||
|
||||
|
||||
class PIOCoreRPC(object):
|
||||
|
||||
def __init__(self):
|
||||
cur_thread_id = thread.get_ident()
|
||||
PIOCoreRPC.thread_stdout = ThreadSafeStdBuffer(sys.stdout,
|
||||
cur_thread_id)
|
||||
PIOCoreRPC.thread_stderr = ThreadSafeStdBuffer(sys.stderr,
|
||||
cur_thread_id)
|
||||
sys.stdout = PIOCoreRPC.thread_stdout
|
||||
sys.stderr = PIOCoreRPC.thread_stderr
|
||||
|
||||
@staticmethod
|
||||
def call(args, options=None):
|
||||
try:
|
||||
@ -40,15 +79,10 @@ class PIOCoreRPC(object):
|
||||
code=4002, message="PIO Core: non-ASCII chars in arguments")
|
||||
|
||||
def _call_cli():
|
||||
outbuff = BytesIO()
|
||||
errbuff = BytesIO()
|
||||
with util.capture_std_streams(outbuff, errbuff):
|
||||
with util.cd((options or {}).get("cwd") or os.getcwd()):
|
||||
exit_code = __main__.main(["-c"] + args)
|
||||
result = (outbuff.getvalue(), errbuff.getvalue(), exit_code)
|
||||
outbuff.close()
|
||||
errbuff.close()
|
||||
return result
|
||||
with util.cd((options or {}).get("cwd") or os.getcwd()):
|
||||
exit_code = __main__.main(["-c"] + args)
|
||||
return (PIOCoreRPC.thread_stdout.getvalue_and_close(),
|
||||
PIOCoreRPC.thread_stderr.getvalue_and_close(), exit_code)
|
||||
|
||||
d = threads.deferToThread(_call_cli)
|
||||
d.addCallback(PIOCoreRPC._call_callback, "--json-output" in args)
|
||||
@ -61,15 +95,7 @@ class PIOCoreRPC(object):
|
||||
text = ("%s\n\n%s" % (out, err)).strip()
|
||||
if code != 0:
|
||||
raise Exception(text)
|
||||
if not json_output:
|
||||
return text
|
||||
try:
|
||||
return json.loads(out)
|
||||
except ValueError as e:
|
||||
if "sh: " in out:
|
||||
return json.loads(
|
||||
re.sub(r"^sh: [^\n]+$", "", out, flags=re.M).strip())
|
||||
raise e
|
||||
return json.loads(out) if json_output else text
|
||||
|
||||
@staticmethod
|
||||
def _call_errback(failure):
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
# pylint: disable=import-error
|
||||
|
||||
import click
|
||||
import jsonrpc
|
||||
from autobahn.twisted.websocket import (WebSocketServerFactory,
|
||||
WebSocketServerProtocol)
|
||||
@ -26,7 +27,7 @@ from platformio.compat import PY2, dump_json_to_unicode, is_bytes
|
||||
class JSONRPCServerProtocol(WebSocketServerProtocol):
|
||||
|
||||
def onMessage(self, payload, isBinary): # pylint: disable=unused-argument
|
||||
# print("> %s" % payload)
|
||||
# click.echo("> %s" % payload)
|
||||
response = jsonrpc.JSONRPCResponseManager.handle(
|
||||
payload, self.factory.dispatcher).data
|
||||
# if error
|
||||
@ -52,11 +53,11 @@ class JSONRPCServerProtocol(WebSocketServerProtocol):
|
||||
message=failure.getErrorMessage())
|
||||
del response["result"]
|
||||
response['error'] = e.error._data # pylint: disable=protected-access
|
||||
print(response['error'])
|
||||
click.secho(str(response['error']), fg="red", err=True)
|
||||
self.sendJSONResponse(response)
|
||||
|
||||
def sendJSONResponse(self, response):
|
||||
# print("< %s" % response)
|
||||
# click.echo("< %s" % response)
|
||||
response = dump_json_to_unicode(response)
|
||||
if not PY2 and not is_bytes(response):
|
||||
response = response.encode("utf-8")
|
||||
|
@ -182,7 +182,7 @@ def platform_frameworks(query, json_output):
|
||||
for framework in util.get_api_result("/frameworks", cache_valid="7d"):
|
||||
if query == "all":
|
||||
query = ""
|
||||
search_data = framework
|
||||
search_data = dump_json_to_unicode(framework)
|
||||
if query and query.lower() not in search_data.lower():
|
||||
continue
|
||||
framework['homepage'] = ("https://platformio.org/frameworks/" +
|
||||
|
Reference in New Issue
Block a user