Introduction
This example allows you to execute commands, openfiles, etc. on a client machine on an intranet web environment.
Background
Some time ago, I was developing an application to control the development of construction projects, so my client wanted to be a web application and that was mandatory. One of the challenges was that within this web application should open drawings and documents by clicking on a link in a web page. As we all know for security reasons this is not possible, so that was when I decided to use a desktop support software to execute these tasks on the client machine. And the glue between the intranet web application and the desktop software was made by THRIFT (an interface definition language and binary communication protocol).
Using the Application
Note: You must run composer to get vendors on symfony ....
I made two sample projects one is a symfony 2.8 web application that acts as a client in the world of thrift, and the other is a C# application that is the server and must run on client machine. All start writing a .thrift file that is an interface definition made up of thrift types and services like this:
namespace csharp ThriftServer
namespace php ThriftSampleBundle.Util
struct FileInf
{
1: string FileName,
2: string extension,
3: bool isDir
}
service OpenFileService{
bool openFile (1:FileInf info,2:string parameters),
list <FileInf> listFolder(1:string path),
}
Here are two definitions of methods, one to list the folders and files in a specified path and another to run or open a specific file, all that on the client machine. Then run the thrift command to generate the client and server codes.
The general syntax is:
thrift --gen <language> <Thrift filename
For PHP:
thrift --gen php OpenFileService.thrift
For C#:
thrift --gen csharp OpenFileService.thrift
So you must implement those two methods on server and call via RPC from client.
Some codes from PHP acting as client, please note as I use "$this->request->getClientIp()
" to get the intranet client IP and know where to connect. So if the web browser has a proxy conf, you must specify that you don't use proxy for this site because otherwise it will get a wrong IP address.
private function openConnection() {
$socket = new TSocket($this->request->getClientIp(), '9090');
$this->transport = new TBufferedTransport($socket);
$protocol = new TBinaryProtocol($this->transport);
$this->client = new OpenFileServiceClient($protocol);
$this->transport->open();
}
To call listFolder($path)
method on C# server from PHP client:
public function listFolder($path) {
try {
$this->openConnection();
$result=$this->client->listFolder($path);
$this->transport->close();
return $result;
}
catch (\Exception $tx) {
echo "ThriftException: ".$tx->getMessage()."\r\n";
}
}
To call openFile($path,$extension)
method on C# server form PHP client:
public function openFile($path,$extension) {
try {
$this->openConnection();
$fileInfo=new FileInf();
$fileInfo->FileName=$path;
$fileInfo->extension=$extension;
$this->client->openFile($fileInfo,null);
$this->transport->close();
}
catch (\Exception $tx) {
echo "ThriftException: ".$tx->getMessage()."\r\n";
}
}
Now let's see how to start the server side in C#:
private void thrift(){
var handler = new OpenFileHandler();
var processor = new OpenFileService.Processor(handler);
TServerTransport transport = new TServerSocket(9090);
TServer server = new TThreadPoolServer(processor, transport);
server.Serve();
}
And the service handler implementation:
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Forms;
namespace ThriftServer
{
public class OpenFileHandler:OpenFileService.Iface
{
public FileInf fileToOpen;
public OpenFileHandler()
{
}
public bool openFile(FileInf info, string parameters)
{
System.Diagnostics.Process.Start(info.FileName);
return true;
}
public IAsyncResult Begin_openFile(AsyncCallback callback,
object state, FileInf info, string parameters)
{
throw new NotImplementedException();
}
public bool End_openFile(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
public List<FileInf> listFolder(string path)
{
DirectoryInfo di=new DirectoryInfo(path);
FileInfo[] files=di.GetFiles();
DirectoryInfo[] directories=di.GetDirectories();
List<FileInf>aux_list=new List<FileInf>();
foreach (DirectoryInfo element in directories) {
FileInf aux_file=new FileInf();
aux_file.FileName=element.FullName;
aux_file.Extension="";
aux_file.IsDir=true;
aux_list.Add(aux_file);
}
foreach (FileInfo element in files) {
FileInf aux_file=new FileInf();
aux_file.FileName=element.FullName;
aux_file.Extension=element.Extension.Replace(".","");
aux_file.IsDir=false;
aux_list.Add(aux_file);
}
return aux_list;
}
public IAsyncResult Begin_listFolder(AsyncCallback callback, object state, string path)
{
throw new NotImplementedException();
}
public List<FileInf> End_listFolder(IAsyncResult asyncResult)
{
throw new NotImplementedException();
}
}
}