Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame^] | 1 | -module(tSocket). |
| 2 | |
| 3 | -include("thrift/thrift.hrl"). |
| 4 | -include("thrift/transport/tTransportException.hrl"). |
| 5 | % -include("thrift/transport/tTransport.hrl"). |
| 6 | -include("thrift/transport/tSocket.hrl"). |
| 7 | |
| 8 | -export([new/0, new/1, new/2, setHandle_MUTABLE/2, open_MUTABLE/1, isOpen/1, write/2, read/2, close_MUTABLE/1, readAll/2]). |
| 9 | |
| 10 | new(Host, Port) -> |
| 11 | #tSocket{host=Host, port=Port, handle=nil}. % WATCH |
| 12 | |
| 13 | new() -> new("localhost", 9090). |
| 14 | new(Host) -> new(Host, 9090). |
| 15 | |
| 16 | setHandle_MUTABLE(This, Handle) -> |
| 17 | This#tSocket{handle=Handle}. |
| 18 | |
| 19 | open_MUTABLE(This) -> |
| 20 | Host = This#tSocket.host, |
| 21 | Port = This#tSocket.port, |
| 22 | Options = [], |
| 23 | |
| 24 | case gen_tcp:connect(Host, Port, Options) of |
| 25 | {error, _} -> |
| 26 | throw(tTransportException:new( |
| 27 | ?tTransportException_NOT_OPEN, |
| 28 | "Could not connect to " ++ Host ++ ":" ++ Port) |
| 29 | ), |
| 30 | {error, This}; % cpiro not reached? |
| 31 | {ok, Socket} -> |
| 32 | {ok, This#tSocket{handle=Socket}} |
| 33 | end. |
| 34 | |
| 35 | handle(This) -> |
| 36 | This#tSocket.handle. |
| 37 | |
| 38 | isOpen(This) -> |
| 39 | handle(This) /= nil. |
| 40 | |
| 41 | write(This, Str) -> |
| 42 | Val = gen_tcp:send(handle(This), Str), |
| 43 | |
| 44 | %% io:format("WRITE |~p|(~p)~n", [Str,Val]), |
| 45 | |
| 46 | case Val of |
| 47 | {error, _} -> |
| 48 | throw(tTransportException:new(?tTransportException_NOT_OPEN, "in write")); |
| 49 | ok -> |
| 50 | ok |
| 51 | end. |
| 52 | |
| 53 | read(This, Sz) -> |
| 54 | case gen_tcp:recv(handle(This), Sz) of |
| 55 | {ok, []} -> |
| 56 | { Host, Port } = { This#tSocket.host, This#tSocket.port }, |
| 57 | throw(tTransportException:new(?tTransportException_UNKNOWN, "TSocket: Could not read " ++ Sz ++ "bytes from " ++ Host ++ ":" ++ Port)); |
| 58 | {ok, Data} -> |
| 59 | Data; |
| 60 | {error, Error} -> |
| 61 | io:format("in tSocket:read/2: gen_tcp:recv(~p, ~p) => {error, ~p}~n", |
| 62 | [handle(This), Sz, Error]), |
| 63 | throw(tTransportException:new(?tTransportException_NOT_OPEN, "in tSocket:read/2: gen_tcp:recv")) |
| 64 | end. |
| 65 | |
| 66 | close_MUTABLE(This) -> |
| 67 | if |
| 68 | This#tSocket.handle == nil -> |
| 69 | This; |
| 70 | true -> |
| 71 | gen_tcp:close(handle(This)), |
| 72 | This#tSocket{handle=nil} |
| 73 | end. |
| 74 | |
| 75 | readAll(This, Sz) -> |
| 76 | readAll_loop(This, Sz, "", 0). |
| 77 | |
| 78 | readAll_loop(This, Sz, Buff, Have) -> |
| 79 | if |
| 80 | Have < Sz -> |
| 81 | Chunk = ?M1(This, read, Sz - Have), |
| 82 | |
| 83 | %% man gen_tcp: |
| 84 | %% exactly Length bytes are returned, or an error; |
| 85 | %% possibly discarding less than Length bytes of data when |
| 86 | %% the socket gets closed from the other side. |
| 87 | |
| 88 | %% io:format("READ |~p|~n", [Chunk]), |
| 89 | |
| 90 | Have1 = Have + (Sz-Have), % length(Chunk) |
| 91 | Buff1 = Buff ++ Chunk, % TODO: ++ efficiency? |
| 92 | readAll_loop(This, Sz, Buff1, Have1); |
| 93 | true -> |
| 94 | Buff |
| 95 | end. |
| 96 | |