c# - Telegram client updates and API requests over same session -


i'm coding custom c# telegram client starting tlsharp , modified in order support layer 54.

i want handle both receiving updates telegram servers , using api without opening separate session this.

the problem multithreaded access socket connected telegram server.

here scheme:

telegramclient <------- socket_1[(session_1)] --------> telegramserver

the problem in order receive updates telegram server use while(true) cycle schematized as:

while(true){     data_cipher = await socket_1.receive() // listen new stuff socket_1     data_plain  = decrypt(data_cipher)  // decrypt      processupdate(data_plain)  // process update } 

now if want ,for example, query telegram servers list of chats in registered, have access socket_1 in order send request, , wait answer, socket_1 in listening , can't access it.

one solution use vector of request processed after update has been received, idea this:

list<request> pending_requests = new list<request>() // list of requests added thread       while(true){          data_cipher = await socket_1.receive() // listen new stuff socket_1         data_plain  = decrypt(data_cipher)  // decrypt              processupdate(data_plain)  // process update          if(pending_requests.count != 0){             foreach(request r in pending_requests ){                      processrequest(r)                 }             }     } 

this solution quite horrible, since process request after update, , no update = no request processed...

another possibility use kind of lock mechanism following scheme this:

//thread_updater //-------------------------------------------- while(true){          lock(socket_1){     data_cipher = await socket_1.receive() // listen new stuff socket_1     }      data_plain  = decrypt(data_cipher)  // decrypt          handleupdate(data_plain)  // process update  } --------------------------------------------   //thread_requests //-------------------------------------------- request r = new request(<stuff>);  lock(socket_1){    await sendrequest(r,socket_1) }  -------------------------------------------- 

the big problem once thread_updater takes lock, never release until update has been received... same problem before. i've tried play cancellationtasks or socket timeout, felt i'm taking wrong path.

is there elegant solution/pattern in order handle in neat way? said , don't want open 2 sessions since logically wrong ( having 2 clients in order handle receiving of updates , sending messages ).

there simpler way this.

this have done in vb.net, should work in c#.

  • setup socket , connect telegram servers, listening data
  • buffer data received
  • process received data - decode tl types received telegram , either store/ react i.e send messages in response have received
  • while listening, can send messages through same socket

sample code

region "variables"

    const buffer_size = 1024 * 64      private soc socket     private ep endpoint     private connected boolean     private efsent boolean     private new autoresetevent(false) #end region  #region "network"     public sub connect(optional ip string = "149.154.167.40", optional port integer = 443)         soc = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp) {.sendbuffersize = buffer_size, .sendtimeout = 3000}          try             ep = getipendpointfromhostname(ip, port)              dim arg = new socketasynceventargs {.remoteendpoint = ep, .usertoken = "connect_args"}             addhandler arg.completed, addressof io_handler              while not connected                 try                     if not soc.connectasync(arg)                         io_handler(soc, arg)                     end if                      are.waitone(4000)                 catch ex exception                     thread.sleep(1000)                 end try             end while          catch ex exception             log("connect: " & ex.tostring, consolecolor.red, true)         end try          readdata()     end sub      public sub disconnect()         connected = false         loggedin = false          soc.disconnect(false)         soc = nothing          log("disconnect", consolecolor.darkyellow, true, true, true)     end sub      private sub send(m plainmessage)         senddata(m.data, true)     end sub      private sub send(m encryptedmessage)         senddata(m.data, true)     end sub      private sub senddata(b() byte, optional read boolean = false)         b = tcppack(b)          dim arg = new socketasynceventargs {.remoteendpoint = ep, .usertoken = "send_args"}         addhandler arg.completed, addressof io_handler         arg.setbuffer(b, 0, b.length)          try             if not soc.sendasync(arg)                 io_handler(soc, arg)             end if         catch ex exception             log("senddata: " & ex.tostring, consolecolor.red)         end try     end sub      private sub io_handler(sender object, e socketasynceventargs)         select case e.socketerror             case socketerror.success                 select case e.lastoperation                     case socketasyncoperation.connect 'a socket connect operation.                         connected = true                         log("connected " & e.connectsocket.remoteendpoint.tostring, consolecolor.green)                         are.set()                     case socketasyncoperation.disconnect                         connected = false                         raiseevent disconneted()                     case socketasyncoperation.receive 'a socket receive operation.                         if e.bytestransferred = 0 'no pending data                             log("the remote end has closed connection.")                             if connected                                 readdata()                             end if                              connected = false                             loggedin = false                              exit sub                         end if                         handledata(e)                 end select             case socketerror.connectionaborted                 raiseevent disconneted()         end select     end sub      private function getipendpointfromhostname(hostname string, port integer) ipendpoint         dim addresses = system.net.dns.gethostaddresses(hostname)         if addresses.length = 0             log("unable retrieve address specified host name:  " & hostname, consolecolor.red)             return nothing         end if         return new ipendpoint(addresses(0), port)     end function      private function tcppack(b byte()) byte()         dim = new list(of byte)         dim len = cbyte(b.length / 4)          if efsent = false 'tcp abridged version             efsent = true             a.add(&hef)         end if          if len >= &h7f             a.add(&h7f)             a.addrange(bitconverter.getbytes(len)) '         else             a.add(len)         end if          a.addrange(b) 'data, no sequence number, no crc32          return a.toarray     end function      private sub readdata()         dim arg = new socketasynceventargs {.remoteendpoint = ep, .usertoken = "read_args"}         addhandler arg.completed, addressof io_handler          dim b(buffer_size - 1) byte         arg.setbuffer(b, 0, buffer_size)          try             if not soc.receiveasync(arg)                 io_handler(soc, arg)             end if         catch ex exception             log("readmessages: " & ex.tostring, consolecolor.red)         end try     end sub      private sub handledata(e socketasynceventargs)         log("<< " & b2h(e.buffer, 0, e.bytestransferred), consolecolor.darkgray, true, logtime:=false)         try             dim len integer = e.buffer(0)             dim start = 1              if len = &h7f                 len = e.buffer(1)                 len += e.buffer(2) << 8                 len += e.buffer(3) << 16                 start = 4             end if              len = 4 * len              dim d(len - 1) byte             array.copy(e.buffer, start, d, 0, len)              processresponse(d)         catch ex exception          end try          readdata()     end sub      private sub processresponse(data byte())         'process data received - identify tl types returned telegram, store / handle each required     end sub #end region 

Comments

Popular posts from this blog

unity3d - Rotate an object to face an opposite direction -

angular - Is it possible to get native element for formControl? -

javascript - Why jQuery Select box change event is now working? -