mirror of
https://github.com/platformio/platformio-core.git
synced 2025-07-30 01:57:13 +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 json
|
||||||
import os
|
import os
|
||||||
import re
|
import sys
|
||||||
|
import thread
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import jsonrpc # pylint: disable=import-error
|
import jsonrpc # pylint: disable=import-error
|
||||||
@ -26,8 +27,46 @@ from platformio import __main__, __version__, util
|
|||||||
from platformio.compat import string_types
|
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):
|
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
|
@staticmethod
|
||||||
def call(args, options=None):
|
def call(args, options=None):
|
||||||
try:
|
try:
|
||||||
@ -40,15 +79,10 @@ class PIOCoreRPC(object):
|
|||||||
code=4002, message="PIO Core: non-ASCII chars in arguments")
|
code=4002, message="PIO Core: non-ASCII chars in arguments")
|
||||||
|
|
||||||
def _call_cli():
|
def _call_cli():
|
||||||
outbuff = BytesIO()
|
with util.cd((options or {}).get("cwd") or os.getcwd()):
|
||||||
errbuff = BytesIO()
|
exit_code = __main__.main(["-c"] + args)
|
||||||
with util.capture_std_streams(outbuff, errbuff):
|
return (PIOCoreRPC.thread_stdout.getvalue_and_close(),
|
||||||
with util.cd((options or {}).get("cwd") or os.getcwd()):
|
PIOCoreRPC.thread_stderr.getvalue_and_close(), exit_code)
|
||||||
exit_code = __main__.main(["-c"] + args)
|
|
||||||
result = (outbuff.getvalue(), errbuff.getvalue(), exit_code)
|
|
||||||
outbuff.close()
|
|
||||||
errbuff.close()
|
|
||||||
return result
|
|
||||||
|
|
||||||
d = threads.deferToThread(_call_cli)
|
d = threads.deferToThread(_call_cli)
|
||||||
d.addCallback(PIOCoreRPC._call_callback, "--json-output" in args)
|
d.addCallback(PIOCoreRPC._call_callback, "--json-output" in args)
|
||||||
@ -61,15 +95,7 @@ class PIOCoreRPC(object):
|
|||||||
text = ("%s\n\n%s" % (out, err)).strip()
|
text = ("%s\n\n%s" % (out, err)).strip()
|
||||||
if code != 0:
|
if code != 0:
|
||||||
raise Exception(text)
|
raise Exception(text)
|
||||||
if not json_output:
|
return json.loads(out) if json_output else text
|
||||||
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
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _call_errback(failure):
|
def _call_errback(failure):
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
# pylint: disable=import-error
|
# pylint: disable=import-error
|
||||||
|
|
||||||
|
import click
|
||||||
import jsonrpc
|
import jsonrpc
|
||||||
from autobahn.twisted.websocket import (WebSocketServerFactory,
|
from autobahn.twisted.websocket import (WebSocketServerFactory,
|
||||||
WebSocketServerProtocol)
|
WebSocketServerProtocol)
|
||||||
@ -26,7 +27,7 @@ from platformio.compat import PY2, dump_json_to_unicode, is_bytes
|
|||||||
class JSONRPCServerProtocol(WebSocketServerProtocol):
|
class JSONRPCServerProtocol(WebSocketServerProtocol):
|
||||||
|
|
||||||
def onMessage(self, payload, isBinary): # pylint: disable=unused-argument
|
def onMessage(self, payload, isBinary): # pylint: disable=unused-argument
|
||||||
# print("> %s" % payload)
|
# click.echo("> %s" % payload)
|
||||||
response = jsonrpc.JSONRPCResponseManager.handle(
|
response = jsonrpc.JSONRPCResponseManager.handle(
|
||||||
payload, self.factory.dispatcher).data
|
payload, self.factory.dispatcher).data
|
||||||
# if error
|
# if error
|
||||||
@ -52,11 +53,11 @@ class JSONRPCServerProtocol(WebSocketServerProtocol):
|
|||||||
message=failure.getErrorMessage())
|
message=failure.getErrorMessage())
|
||||||
del response["result"]
|
del response["result"]
|
||||||
response['error'] = e.error._data # pylint: disable=protected-access
|
response['error'] = e.error._data # pylint: disable=protected-access
|
||||||
print(response['error'])
|
click.secho(str(response['error']), fg="red", err=True)
|
||||||
self.sendJSONResponse(response)
|
self.sendJSONResponse(response)
|
||||||
|
|
||||||
def sendJSONResponse(self, response):
|
def sendJSONResponse(self, response):
|
||||||
# print("< %s" % response)
|
# click.echo("< %s" % response)
|
||||||
response = dump_json_to_unicode(response)
|
response = dump_json_to_unicode(response)
|
||||||
if not PY2 and not is_bytes(response):
|
if not PY2 and not is_bytes(response):
|
||||||
response = response.encode("utf-8")
|
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"):
|
for framework in util.get_api_result("/frameworks", cache_valid="7d"):
|
||||||
if query == "all":
|
if query == "all":
|
||||||
query = ""
|
query = ""
|
||||||
search_data = framework
|
search_data = dump_json_to_unicode(framework)
|
||||||
if query and query.lower() not in search_data.lower():
|
if query and query.lower() not in search_data.lower():
|
||||||
continue
|
continue
|
||||||
framework['homepage'] = ("https://platformio.org/frameworks/" +
|
framework['homepage'] = ("https://platformio.org/frameworks/" +
|
||||||
|
Reference in New Issue
Block a user