1# Building of samples for different platforms
2
3# Requirements
4- NET Core Standard 3.1 (LTS) runtime or SDK (see below for further info)
5
6# How to build
7- Download and install the latest .NET Core SDK for your platform https://dotnet.microsoft.com/download/dotnet-core
8- Ensure that you have thrift.exe which supports netstd lib and it added to PATH
9- Go to current folder
10- Run **build.sh** or **build.cmd** from the root of cloned repository
11- Check tests in **src/Tests** folder
12- Continue with /tutorials/netstd
13
14# How to run
15
16Depending on the platform, the name of the generated executables will vary. On Linux, it is just "Client" or "Server", on Windows it is "Client.exe" and "Server.exe". In the following, we use the abbreviated form "Client" and "Server".
17
18- build
19- go to folder (Client/Server)
20- run the generated executables: server first, then client from a second console
21
22# Known issues
23- In trace logging mode you can see some not important internal exceptions
24
25# Running of samples
26On machines that do not have the SDK installed, you need to install the NET Core runtime first. The SDK is only needed to build programs, otherwise the runtime is sufficient.
27
28# NetCore Server
29
30Usage:
31
32    Server -help
33        will diplay help information
34
35    Server -tr:<transport> -pr:<protocol>
36        will run server with specified arguments (tcp transport and binary protocol by default)
37
38Options:
39
40    -tr (transport):
41        tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090)
42        namedpipe - namedpipe transport will be used (pipe address - "".test"")
43        http - http transport will be used (http address - ""localhost:9090"")
44        tcptls - tcp transport with tls will be used (host - ""localhost"", port - 9090)
45
46    -bf (buffering):
47        none - (default) no transport factory will be used
48        buffered - buffered transport factory will be used
49        framed - framed transport factory will be used (this must match the client)
50
51    -pr (protocol):
52        binary - (default) binary protocol will be used
53        compact - compact protocol will be used
54        json - json protocol will be used
55        multiplexed - multiplexed protocol will be used
56
57Sample:
58
59    Server -tr:tcp
60
61**Remarks**:
62
63    For TcpTls mode certificate's file ThriftTest.pfx should be in directory with binaries in case of command line usage (or at project level in case of debugging from IDE).
64    Password for certificate - "ThriftTest".
65
66
67
68# NetCore Client
69
70Usage:
71
72    Client -help
73        will diplay help information
74
75    Client -tr:<transport> -pr:<protocol> -mc:<numClients>
76        will run client with specified arguments (tcp transport and binary protocol by default)
77
78Options:
79
80    -tr (transport):
81        tcp - (default) tcp transport will be used (host - ""localhost"", port - 9090)
82        namedpipe - namedpipe transport will be used (pipe address - "".test"")
83        http - http transport will be used (address - ""http://localhost:9090"")
84        tcptls - tcp tls transport will be used (host - ""localhost"", port - 9090)
85
86    -bf (buffering):
87        none - (default) no transport factory will be used
88        buffered - buffered transport factory will be used
89        framed - framed transport factory will be used (this must match the client)
90
91    -pr (protocol):
92        binary - (default) binary protocol will be used
93        compact - compact protocol will be used
94        json - json protocol will be used
95        multiplexed - multiplexed protocol will be used
96
97    -mc (multiple clients):
98        <numClients> - number of multiple clients to connect to server (max 100, default 1)
99
100Sample:
101
102    Client -tr:tcp -pr:binary -mc:10
103
104Remarks:
105
106    For TcpTls mode certificate's file ThriftTest.pfx should be in directory
107	with binaries in case of command line usage (or at project level in case of debugging from IDE).
108    Password for certificate - "ThriftTest".
109
110# How to test communication between NetCore and Python
111
112* Generate code with the latest **thrift** utility
113* Ensure that **thrift** generated folder **gen-py** with generated code for Python exists
114* Create **client.py** and **server.py** from the code examples below and save them to the folder with previosly generated folder **gen-py**
115* Run netstd samples (client and server) and python samples (client and server)
116
117Remarks:
118
119Samples of client and server code below use correct methods (operations)
120and fields (properties) according to generated contracts from *.thrift files
121
122At Windows 10 add record **127.0.0.1 testserver** to **C:\Windows\System32\drivers\etc\hosts** file
123for correct work of python server
124
125
126**Python Client:**
127
128```python
129import sys
130import glob
131sys.path.append('gen-py')
132
133from tutorial import Calculator
134from tutorial.ttypes import InvalidOperation, Operation, Work
135
136from thrift import Thrift
137from thrift.transport import TSocket
138from thrift.transport import TTransport
139from thrift.protocol import TBinaryProtocol
140
141
142def main():
143    # Make socket
144    transport = TSocket.TSocket('127.0.0.1', 9090)
145
146    # Buffering is critical. Raw sockets are very slow
147    transport = TTransport.TBufferedTransport(transport)
148
149    # Wrap in a protocol
150    protocol = TBinaryProtocol.TBinaryProtocol(transport)
151
152    # Create a client to use the protocol encoder
153    client = Calculator.Client(protocol)
154
155    # Connect!
156    transport.open()
157
158    client.Ping()
159    print('ping()')
160
161    sum = client.Add(1, 1)
162    print(('1+1=%d' % (sum)))
163
164    work = Work()
165
166    work.Op = Operation.Divide
167    work.Num1 = 1
168    work.Num2 = 0
169
170    try:
171        quotient = client.Calculate(1, work)
172        print('Whoa? You know how to divide by zero?')
173        print('FYI the answer is %d' % quotient)
174    except InvalidOperation as e:
175        print(('InvalidOperation: %r' % e))
176
177    work.Op = Operation.Substract
178    work.Num1 = 15
179    work.Num2 = 10
180
181    diff = client.Calculate(1, work)
182    print(('15-10=%d' % (diff)))
183
184    log = client.GetStruct(1)
185    print(('Check log: %s' % (log.Value)))
186
187    client.Zip()
188    print('zip()')
189
190    # Close!
191    transport.close()
192
193if __name__ == '__main__':
194  try:
195    main()
196  except Thrift.TException as tx:
197    print('%s' % tx.message)
198```
199
200
201**Python Server:**
202
203
204```python
205import glob
206import sys
207sys.path.append('gen-py')
208
209from tutorial import Calculator
210from tutorial.ttypes import InvalidOperation, Operation
211
212from shared.ttypes import SharedStruct
213
214from thrift.transport import TSocket
215from thrift.transport import TTransport
216from thrift.protocol import TBinaryProtocol
217from thrift.server import TServer
218
219
220class CalculatorHandler:
221    def __init__(self):
222        self.log = {}
223
224    def Ping(self):
225        print('ping()')
226
227    def Add(self, n1, n2):
228        print('add(%d,%d)' % (n1, n2))
229        return n1 + n2
230
231    def Calculate(self, logid, work):
232        print('calculate(%d, %r)' % (logid, work))
233
234        if work.Op == Operation.Add:
235            val = work.Num1 + work.Num2
236        elif work.Op == Operation.Substract:
237            val = work.Num1 - work.Num2
238        elif work.Op == Operation.Multiply:
239            val = work.Num1 * work.Num2
240        elif work.Op == Operation.Divide:
241            if work.Num2 == 0:
242                raise InvalidOperation(work.Op, 'Cannot divide by 0')
243            val = work.Num1 / work.Num2
244        else:
245            raise InvalidOperation(work.Op, 'Invalid operation')
246
247        log = SharedStruct()
248        log.Key = logid
249        log.Value = '%d' % (val)
250        self.log[logid] = log
251
252        return val
253
254    def GetStruct(self, key):
255        print('getStruct(%d)' % (key))
256        return self.log[key]
257
258    def Zip(self):
259        print('zip()')
260
261if __name__ == '__main__':
262    handler = CalculatorHandler()
263    processor = Calculator.Processor(handler)
264    transport = TSocket.TServerSocket(host="testserver", port=9090)
265    tfactory = TTransport.TBufferedTransportFactory()
266    pfactory = TBinaryProtocol.TBinaryProtocolFactory()
267
268    server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)
269    print('Starting the server...')
270    server.serve()
271    print('done.')
272
273    # You could do one of these for a multithreaded server
274    # server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)
275    # server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)
276```
277