B4J Question Server Servlet Api sending binary stream

imbault

Well-Known Member
Licensed User
Longtime User
Hi, if someone can help, surely @Erel I guess

I'm implementing a Server that upload a file depending of parameters
server call is that way
http://127.0.0.1:51040/getinvoice?login=pat&password=123456&factkey=smu160761.pdf

it should return binary stream of the pdf

Main is straightforward
B4X:
Sub AppStart (Args() As String)
    config = File.ReadMap(File.DirApp, "config.txt")
    srvr.Initialize("srvr")
    srvr.Port = config.Get("PushServerPort")
    srvr.AddHandler("/getinvoice", "GetInvoice", False)
    srvr.Start
    Log("server is listening on port: " & srvr.Port)
    StartMessageLoop
End Sub

In GetInvoice module handle
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
    If req.GetParameter("login") <> Main.config.Get("PushWynbeLogin") Then
        resp.SendError(500, "1")     ' 1 Non authetifié
        Return
    End If
    If req.GetParameter("password") <> Main.config.Get("PushWynbePassword") Then
        resp.SendError(500, "1") ' 1 Non authetifié
        Return
    End If
    factkey = req.GetParameter("factkey")
        SMB1.Initialize("SMB1")
        SMB1.SetCredentials(Main.config.Get("SMBName"),Main.config.Get("SMBPassword"),Main.config.Get("SMBDomain"))

        cFile = cFact & ".pdf"
        SMBPath = Main.config.Get("PushInvPath") &  cTri & "/" & cYear & "/"
        Dim out As OutputStream
        out = File.OpenOutput(File.DirApp, "toto.pdf", False)
           cout.Initialize(out)
        SMB1.DownloadFile2(SMBPath,cFile,cout,True)

At the end, I don't know how to send the binary Output Stream
resp.ContentType="application/pdf" ???
resp.OutputStream.... ???

Help Please
 
Last edited:

imbault

Well-Known Member
Licensed User
Longtime User
SMB1 is used in a Windows Shared Folder, b4a Server will be in DMZ.

The link you send me is weird, in german, wrong link?

Patrick
 
Last edited:
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
What is the purpose of SMB1 here?

You can see an example of a server that sends files here: https://www.b4x.com/android/forum/t...app-to-your-b4j-server-over-the-internet.3720

Sorry the GetInvoice module was incorrect:
B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)

         FactFile = req.GetParameter("factfile")

        SMB1.Initialize("SMB1")
        SMB1.SetCredentials(Main.config.Get("SMBName"),Main.config.Get("SMBPassword"),Main.config.Get("SMBDomain"))

        SMBPath = Main.config.Get("PushInvPath")

        Dim out As OutputStream
      out.InitializeToBytesArray(0)
  
        SMB1.DownloadFile2(SMBPath,Factfile,out,True)
' return out???
 
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Sorry @Erel , I know you are super busy, but can you tell me is that Servlet code is correct to send binary stream of file:

B4X:
Sub Handle(req As ServletRequest, resp As ServletResponse)
    Dim FactFile a string   
   
    Private bufferSize As Int = 1000
   
    FactFile = req.GetParameter("factfile")
   
    SMB1.Initialize("SMB1")
    SMB1.SetCredentials(Main.config.Get("SMBName"),Main.config.Get("SMBPassword"),Main.config.Get("SMBDomain"))
      
    Dim out As OutputStream    
    out.InitializeToBytesArray(0)

    StopMessageLoop
    SMB1.DownloadFile2(SMBPath,FactFile,out,False)
    out.Flush

    resp.OutputStream.InitializeToBytesArray(bufferSize)
    resp.OutputStream.WriteBytes(out.ToBytesArray,0,out.ToBytesArray.Length)
End Sub


Sub SMB1_DownloadCompleted (Url As String, RemoteFile As String, Success As Boolean)
    StartMessageLoop
End Sub
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
The problem is not related to binary streaming. The problem here is how to make the server wait for SMB to complete before committing the response.

For this to work you need to:
1. Call SMB1.DownloadFile2.
2. Call StartMessageLoop
3. In DownloadCompleted call StopMessageLoop.
The code execution will continue from the StartMessageLoop place.

Now you should use File.Copy2 to copy the downloaded file to resp.OutputStream (do not initialize it as it will create a new irrelevant output stream).
 
Upvote 0

imbault

Well-Known Member
Licensed User
Longtime User
Thanks @Erel , you are right concerning SMB.

This is what I've done, maybe it will help someone else, I didn't think to use File.Copy2, thanks master.

Is that code correct? I use only one stream

B4X:
'Handler class
Sub Class_Globals
    Dim SMB1 As SMB
    Dim out As OutputStream
End Sub

Public Sub Initialize
  
End Sub

Sub Handle(req As ServletRequest, resp As ServletResponse)
    Dim FactFile As String
  
    FactFile = req.GetParameter("factfile")
  
    SMB1.Initialize("SMB1")
    SMB1.SetCredentials(Main.config.Get("SMBName"),Main.config.Get("SMBPassword"),Main.config.Get("SMBDomain"))

    SMBPath = Main.config.Get("PushInvPath")

    out.InitializeToBytesArray(0)

    SMB1.DownloadFile2(SMBPath,FactFile,out,False)
    StartMessageLoop

    resp.ContentType="application/octet-stream"
    resp.OutputStream.WriteBytes(out.ToBytesArray,0,out.ToBytesArray.Length)      
  
End Sub



Sub SMB1_DownloadCompleted (Url As String, RemoteFile As String, Success As Boolean)
      out.Flush
    StopMessageLoop
End Sub
 
Last edited:
Upvote 0
Top