aboutsummaryrefslogtreecommitdiff
path: root/dialoguer/__init__.py
blob: 21c51d2e4027772b9d8d48928208b9eb8c7c16c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import os
import subprocess
import threading
import socket
import uuid
from .binary_conversion import bin_conv
from .data_type_ref import data_type_dict

HEADER = 2048
PORT = 6011
SERVER = 'localhost'
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)

# could there be a defined sub-class that has all the sockets connection functions?
# then the dialogue class launches and connects and loops
class Dialogue:
	def __init__(self, file_name, wait = True):
		self.file_name = os.path.basename(file_name)
		if bool(os.path.dirname(file_name)):
			self.file_path = file_name
		else:
			self.file_path = os.path.join(os.getcwd(), file_name)
		self.ext = file_name.split('.')[-1]
		self.uuid = str(uuid.uuid4())
		self.conn = None
		self.addr = None
		self.connected = False
		self.active = False
		if wait: 
			self.open()

	def execute_context_script(self):
		context_file = __file__.replace('__init__.py', 'context_script.r')

		subprocess.run(
			f'Rscript {context_file} {self.uuid} {self.file_path}',
			cwd = os.getcwd(),
			start_new_session = True
			)

	def establish_connection(self):
		while not self.connected:
			server.listen()
			self.conn, self.addr = server.accept()
			uuid_chk = self.recv()
			self.connected = self.uuid == uuid_chk
			self.send(self.uuid)
			if not self.connected:
				self.conn.close()
	
	def open(self):
		self._connect = threading.Thread(target=self.establish_connection)
		self._launch = threading.Thread(target=self.execute_context_script)

		self._connect.start()
		self._launch.start()
		self._connect.join()

		data = self.recv(set_data_type=bool)
		self.active = (data == True)
	
	def send(self, data, send_data_type = False):
		if send_data_type:
			data_type_name = type(data)
			data_type_name = data_type_name.__name__
			data_type_name = bin_conv(data_type_name)
			self.conn.send(data_type_name)
			recv_chk = self.recv(set_data_type=bool)
		bin_data = bin_conv(data)
		self.conn.send(bin_data)

	# I still want to consolidate the recv_data_type and set_data_type args
	def recv(self, recv_data_type = False, set_data_type = str):
		if recv_data_type:
			data_type_name = self.conn.recv(HEADER)
			while data_type_name == b'\x00':
				data_type_name = self.conn.recv(HEADER)
			data_type_name = bin_conv(data_type_name, str)
			data_type = data_type_dict[data_type_name]
			self.send(True)
		else:
			data_type = set_data_type

		data = self.conn.recv(HEADER)
		while data == b'\x00':
			data = self.conn.recv(HEADER)
		data = bin_conv(data, data_type)

		return data

	def import_variable(self, var_name):
		self.send(1)
		recv_chk = self.recv(set_data_type=bool)
		self.send(var_name, False)
		val = self.recv(True)
		return val

	def assign_variable(self, var_name, var_val):
		self.send(3)
		recv_chk = self.recv(set_data_type=bool)
		self.send(var_name, False)
		recv_chk = self.recv(set_data_type=bool)
		self.send(var_val, True)
		recv_chk = self.recv(set_data_type=bool)

	def evaluate_expression(self, method_name, *args, **kwargs):
		self.send(2)
		recv_chk = self.recv(set_data_type=bool)
		#send number of arguments
		self.send(len(args))
		recv_chk = self.recv(set_data_type=bool)
		#send number of keyword arguments
		self.send(len(kwargs))
		recv_chk = self.recv(set_data_type=bool)
		#send method name
		self.send(method_name)
		recv_chk = self.recv(set_data_type=bool)
		#send arguments
		for arg in args:
			self.send(arg, True)
			recv_chk = self.recv(set_data_type=bool)
		#send keyword arguments
		for kw in kwargs:
			self.send(kw)
			recv_chk = self.recv(set_data_type=bool)
			self.send(kwargs[kw], True)
			recv_chk = self.recv(set_data_type=bool)
		result = self.recv(True)
		return result


	def close(self):
		self.send(0)
		self._launch.join()
		self.conn.close()
		self.conn = None
		self.addr = None
		self.connected = False
		self.active = False