Browse files

parsing nicely initial request from flex client upon very first invoc…

…ation
  • Loading branch information...
1 parent 0b861f1 commit 0cc401d7dfc7ce30a0033af77f982319d3a21d0a @trung committed Oct 2, 2009
View
1 temp/server/action_message.hrl
@@ -11,6 +11,7 @@
-define(AMF_CONTENT_TYPE, "application/x-amf").
-define(XML_CONTENT_TYPE, "application/xml").
+-define(OBJECT_REF_TABLE_AMF0, objectRefTableAmf0).
-define(OBJECT_REF_TABLE, objectRefTable).
-define(TRAIT_REF_TABLE, traitRefTable).
-define(STRING_REF_TABLE, stringRefTable).
View
37 temp/server/amf0.erl
@@ -22,10 +22,11 @@
-define(recordset_marker, 16#0E). %% reserved, not supported
-define(xml_document_marker, 16#0F).
-define(typed_object_marker, 16#10).
--define(avm_plus_object_marker, 16#11).
+-define(avm_plus_object_marker, 16#11). %% define AMF3 must be used
%% Clear ETS tables
reset() ->
+ _ = ref_table:clear(?OBJECT_REF_TABLE_AMF0),
_ = amf3:reset(),
{ok}.
@@ -59,23 +60,33 @@ read_boolean(<<Value:8, Rest/binary>>) ->
read_boolean(Something) ->
{bad, {"Can't read boolean", Something}}.
+read_strict_array(Bin, Count, Total, Acc) when Count == Total ->
+ {ok, Acc, Bin};
+read_strict_array(Bin, Count, Total, Acc) ->
+ {ok, Obj, NextBin} = read_object(Bin),
+ read_strict_array(NextBin, Count + 1, Total, Acc ++ [Obj]).
+
+read_strict_array(Bin) ->
+ {ok, Size, BinAfterSize} = read_u32(Bin),
+ read_strict_array(BinAfterSize, 0, Size, []).
+
%% return {ok, value/Value, Rest} or {bad, Reason}
read_object(<<?number_marker:8, Rest/binary>>) -> read_number(Rest);
read_object(<<?boolean_marker:8, Rest/binary>>) -> read_boolean(Rest);
read_object(<<?string_marker:8, Rest/binary>>) -> read_string(Rest);
-read_object(<<?object_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?object_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE,?LINE, Rest}};
read_object(<<?movieclip_marker:8, Rest/binary>>) -> {bad, {"Reserved, not supported", Rest}};
read_object(<<?null_marker:8, Rest/binary>>) -> {ok, null, Rest};
-read_object(<<?undefined_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?reference_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?ecma_array_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?object_end_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?strict_array_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?date_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?long_string_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?unsupported_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?recordset_marker:8, Rest/binary>>) -> {bad, {"Reserved, not supported", Rest}};
-read_object(<<?xml_document_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
-read_object(<<?typed_object_marker:8, Rest/binary>>) -> {bad, {"Not supported", Rest}};
+read_object(<<?undefined_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?reference_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?ecma_array_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?object_end_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?strict_array_marker:8, Rest/binary>>) -> read_strict_array(Rest);
+read_object(<<?date_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?long_string_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?unsupported_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?recordset_marker:8, Rest/binary>>) -> {bad, {"Reserved, not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?xml_document_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
+read_object(<<?typed_object_marker:8, Rest/binary>>) -> {bad, {"Not supported",?MODULE, ?LINE, Rest}};
%% switch to AMF3
read_object(<<?avm_plus_object_marker:8, Rest/binary>>) -> amf3:read_object(Rest).
View
110 temp/server/amf3.erl
@@ -1,5 +1,5 @@
-module(amf3).
--export([read_object/1, reset/0]).
+-export([read_object/1, reset/0, read_uint_29/1]).
-include("action_message.hrl").
-include("messages.hrl").
@@ -20,55 +20,11 @@
%% Clear ETS tables: string, object and trait
reset() ->
- _ = clear(?OBJECT_REF_TABLE),
- _ = clear(?TRAIT_REF_TABLE),
- _ = clear(?STRING_REF_TABLE),
+ _ = ref_table:clear(?OBJECT_REF_TABLE),
+ _ = ref_table:clear(?TRAIT_REF_TABLE),
+ _ = ref_table:clear(?STRING_REF_TABLE),
{ok}.
-%% delete all objects
-clear(TableName) ->
- try ets:delete_all_objects(TableName) of
- true ->
- _ = ets:insert(TableName, {counter, 0}),
- {ok}
- catch
- error:Error ->
- {bad, Error}
- end.
-
-%% Make sure the table exist, if not, create new one
-sure_exist(TableName) ->
- case ets:info(TableName) of
- undefined ->
- ets:new(TableName, [named_table]),
- _ = ets:insert(TableName, {counter, 0}),
- {ok, created};
- _ ->
- {ok, exists}
- end.
-
-%% wrapper of ets:insert, just make sure the table exists
-insert(TableName, Obj) ->
- _ = sure_exist(TableName),
- {ok, Count} = read(TableName, counter),
- io:fwrite("Inserting into ~p - index: ~p - value: ~p ~n", [TableName, Count, Obj]),
- _ = ets:insert(TableName, {Count, Obj}),
- _ = ets:insert(TableName, {counter, Count+1}),
- {ok, inserted, Count}.
-
-%% wrapper of ets:lookup
-read(TableName, Ref) ->
- io:fwrite("Read from ~p with index ~p got value ", [TableName, Ref]),
- case ets:lookup(TableName, Ref) of
- [] ->
- {bad, {not_found, TableName, Ref}};
- [{counter, Count}|_] ->
- {ok, Count};
- [{_Idx, Obj}|_] ->
-%% io:fwrite("~p~n", [Obj]),
- {ok, Obj}
- end.
-
%% The high bit of the first 3 bytes are used as flags to determine
%% whether the next byte is part of the integer.
%% With up to 3 bits of the 32 bits being used as flags,
@@ -84,43 +40,43 @@ read(TableName, Ref) ->
read_uint_29(<<2#0:1, First:7, Rest/binary>>) ->
{ok, First, Rest};
read_uint_29(<<2#1:1, First:7, 2#0:1, Second:7, Rest/binary>>) ->
- {ok, ((First bor 16#80) bsl 8) bor Second, Rest};
+ {ok, ((First band 16#7F) bsl 7) bor Second, Rest};
read_uint_29(<<2#1:1, First:7, 2#1:1, Second:7, 2#0:1, Third:7, Rest/binary>>) ->
- {ok, ((First bor 16#80) bsl 16) bor ((Second bor 16#80) bsl 8) bor Third, Rest};
+ {ok, ((((First band 16#7F) bsl 7) bor (Second band 16#7F)) bsl 7) bor Third, Rest};
read_uint_29(<<2#1:1, First:7, 2#1:1, Second:7, 2#1:1, Third:7, Forth:8, Rest/binary>>) ->
- {ok, ((First bor 16#80) bsl 24) bor ((Second bor 16#80) bsl 16) bor ((Third bor 16#80) bsl 8) bor Forth, Rest};
+ {ok, (((((First band 16#7F) bsl 7) bor (Second band 16#7F)) bsl 7) bor ((Third band 16#7F) bsl 8)) bor Forth, Rest};
read_uint_29(_) ->
{bad, "Not a binary or number out of range or empty binary"}.
%% Read object from ETS based on the key Ref
%% Return {ok, Obj} or {bad, Reason}
read_object_reference(Ref) ->
- {bad, {"Not yet implemented: read_object_reference", Ref}}.
+ ref_table:read(?OBJECT_REF_TABLE, Ref).
%% Read object from ETS based on the key Ref
%% Return {ok, Obj} or {bad, Reason}
read_trait_reference(Ref) ->
- read(?TRAIT_REF_TABLE, Ref).
+ ref_table:read(?TRAIT_REF_TABLE, Ref).
%% Read object from ETS based on the key Ref
%% Return {ok, Str} or {bad, Reason}
read_string_reference(Ref) ->
- {bad, {"Not yet implemented: read_string_reference", Ref}}.
+ ref_table:read(?STRING_REF_TABLE, Ref).
-write_object_reference(Ref, Obj) ->
- %% TODO store the {Ref, Obj} to ETS
+write_object_reference(Obj) ->
+ {ok, inserted, Ref} = ref_table:insert(?OBJECT_REF_TABLE, Obj),
{ok, Ref, Obj}.
write_trait_reference(Obj) ->
- {ok, inserted, Ref} = insert(?TRAIT_REF_TABLE, Obj),
+ {ok, inserted, Ref} = ref_table:insert(?TRAIT_REF_TABLE, Obj),
{ok, Ref, Obj}.
%% Not store if string is empty
-write_string_reference(Ref, Str) when length(Str) == 0 ->
- {ok, Ref, Str};
+write_string_reference(Str) when length(Str) == 0 ->
+ {ok, -1, Str};
%% Return {ok, Ref, Str}
-write_string_reference(Ref, Str) ->
- %% TODO store the {Ref, Str} to ETS
+write_string_reference(Str) ->
+ {ok, inserted, Ref} = ref_table:insert(?STRING_REF_TABLE, Str),
{ok, Ref, Str}.
%% AMF 0 and AMF 3 use (non-modified) UTF-8 to encode strings. UTF-8
@@ -165,7 +121,7 @@ read_string(Bin) ->
{StrBin, BinAfterStrBin} = split_binary(BinAfterRef, StrLen),
{ok, Str} = binary_to_utf8(StrBin),
%% io:fwrite("StrLen: ~p~nBinString: ~n~p~nString: ~p~n", [StrLen, StrBin, Str]),
- {ok, _, _} = write_string_reference(RefIndex, Str),
+ {ok, _, _} = write_string_reference(Str),
{ok, Str, BinAfterStrBin}
end.
@@ -186,6 +142,7 @@ read_trait(Ref, Bin) ->
Dynamic = (Ref band 8) == 8,
PropertyCount = Ref bsr 4,
{ok, ClassName, BinAfterClassName} = read_string(Bin),
+ io:fwrite("This trait has ~p properties~n", [PropertyCount]),
{ok, Properties, BinAfterProperties} = read_properties(BinAfterClassName, 0, PropertyCount, []),
Trait = #trait{className = ClassName, externalizable = Externalizable, dynamic = Dynamic, properties = Properties},
{ok, _, _} = write_trait_reference(Trait),
@@ -235,12 +192,12 @@ read_array(Bin) ->
length(Map) == 0 ->
%% Read as normal array [Value1, Value2, ...]
{ok, Array, BinAfterArray} = read_dense_array(BinAfterMap, 0, Len, []),
- {ok, _, _} = write_object_reference(IndexRef, Array),
+ {ok, _, _} = write_object_reference(Array),
{ok, Array, BinAfterArray};
true ->
%% Continue read as associative arrray
{ok, MapExt, BinAfterMapExt} = read_associative_array_ext(BinAfterMap, 0, Len, Map),
- {ok, _, _} = write_object_reference(IndexRef, MapExt),
+ {ok, _, _} = write_object_reference(MapExt),
{ok, MapExt, BinAfterMapExt}
end
end.
@@ -250,6 +207,17 @@ is_type(externalizable, true, ?FC_OBJECTPROXY) -> true;
is_type(externalizable, true, _) -> false;
is_type(externalizable, false, _) -> not_externalizable.
+read_object_property(Bin, {dynamic, true}, PropertyMap) when is_list(PropertyMap) ->
+ {ok, PropertyName, BinAfterPropertyName} = read_string(Bin),
+ case length(PropertyName) of
+ 0 ->
+ {ok, PropertyMap, BinAfterPropertyName};
+ _ ->
+ {ok, PropertyValue, BinAfterPropertyValue} = read_object(BinAfterPropertyName),
+ read_object_property(BinAfterPropertyValue, {dynamic, true}, PropertyMap ++ [{PropertyName, PropertyValue}])
+ end;
+read_object_property(Bin, {dynamic, false}, PropertyMap) when is_list(PropertyMap) ->
+ {ok, PropertyMap, Bin};
read_object_property(Bin, [], Object) ->
{ok, Object, Bin};
read_object_property(Bin, [PropertyStr|Tail], PropertyMap) when is_list(PropertyMap) ->
@@ -264,8 +232,9 @@ read_object_property(Bin, [PropertyStr|Tail], Object) ->
read_object_with_trait(Bin, TraitObj) when is_record(TraitObj, trait) ->
case record_utils:fc_to_record(TraitObj#trait.className) of
{ok, undefined} ->
- {ok, PropertyMap, NextBin} = read_object_property(Bin, TraitObj#trait.properties, []),
- {ok, {asObject, PropertyMap}, NextBin};
+ {ok, PropertyMap, BinAfterProperty} = read_object_property(Bin, TraitObj#trait.properties, []),
+ {ok, PropertyMapAll, NextBin} = read_object_property(BinAfterProperty, {dynamic, TraitObj#trait.dynamic}, PropertyMap),
+ {ok, {asObject, PropertyMapAll}, NextBin};
{ok, NewObject} ->
read_object_property(Bin, TraitObj#trait.properties, NewObject)
end.
@@ -282,6 +251,7 @@ read_object(<<?xml_doc_marker:8, Rest/binary>>) -> {bad, {"Not yet implemented
read_object(<<?date_marker:8, Rest/binary>>) -> {bad, {"Not yet implemented marker", Rest}};
read_object(<<?array_marker:8, Rest/binary>>) -> read_array(Rest);
read_object(<<?object_marker:8, Rest/binary>>) ->
+ %% io:fwrite("Reading Ref from ~p got value ", [Rest]),
{ok, Ref, BinAfterRef} = read_uint_29(Rest),
case Ref band 1 of
0 ->
@@ -293,13 +263,17 @@ read_object(<<?object_marker:8, Rest/binary>>) ->
% io:fwrite("Trait: ~p~n", [TraitObj]),
case is_type(externalizable, TraitObj#trait.externalizable, TraitObj#trait.className) of
true ->
- read_object(BinAfterTrait);
+ {ok, Obj, BinAfterObj} = read_object(BinAfterTrait),
+ _ = write_object_reference(Obj),
+ {ok, Obj, BinAfterObj};
false ->
{bad, {"Externalizable class not supported", TraitObj}};
not_externalizable ->
%% subsequence binary contains values in order of property array in TraitObj
%% object will have the format: {object, [{propertyName=term(), Value}, ...]}
- read_object_with_trait(BinAfterTrait, TraitObj)
+ {ok, Obj, BinAfterObj} = read_object_with_trait(BinAfterTrait, TraitObj),
+ _ = write_object_reference(Obj),
+ {ok, Obj, BinAfterObj}
end
end;
read_object(<<?xml_marker:8, Rest/binary>>) -> {bad, {"Not yet implemented marker", Rest}};
View
1 temp/server/flex_classes.hrl
@@ -1,3 +1,4 @@
-define(FC_ARRAYCOLLECTION, "flex.messaging.io.ArrayCollection").
-define(FC_OBJECTPROXY, "flex.messaging.io.ObjectProxy").
-define(FC_REMOTINGMESSAGE, "flex.messaging.messages.RemotingMessage").
+-define(FC_COMMANDMESSAGE, "flex.messaging.messages.CommandMessage").
View
69 temp/server/messages.hrl
@@ -1,22 +1,47 @@
--record(abstract_message, {
- clientId,
- destination = "",
- messageId = "",
- timestamp = 0,
- timeToLive = 0,
- headers = [],
- body
- }).
-
--record(rpc_message, {
- parent = #abstract_message{},
- remoteUsername = "",
- remotePassword = ""
- }).
-
--record(remoting_message, {
- parent = #rpc_message{},
- source = "",
- operation = "",
- parameters = []
- }).
+%% operations for command message
+-define(SUBSCRIBE_OPERATION, 0).
+-define(UNSUBSCRIBE_OPERATION, 1).
+-define(POLL_OPERATION, 2).
+-define(CLIENT_SYNC_OPERATION, 3).
+-define(CLIENT_PING_OPERATION, 4).
+-define(CLUSTER_REQUEST_OPERATION, 5).
+-define(LOGIN_OPERATION, 6).
+-define(LOGOUT_OPERATION, 7).
+-define(SUBSCRIPTION_INVALIDATE_OPERATION, 8).
+-define(MULTI_SUBSCRIBE_OPERATION, 9).
+-define(DISCONNECT_OPERATION, 20).
+-define(UNKNOWN_OPERATION, 1000).
+
+-record(abstract_message, {
+ clientId,
+ destination = "",
+ messageId = "",
+ timestamp = 0,
+ timeToLive = 0,
+ headers = [],
+ body
+ }).
+
+-record(rpc_message, {
+ parent = #abstract_message{},
+ remoteUsername = "",
+ remotePassword = ""
+ }).
+
+-record(remoting_message, {
+ parent = #rpc_message{},
+ source = "",
+ operation = "",
+ parameters = []
+ }).
+
+-record(async_message, {
+ parent = #abstract_message{},
+ correlationId = "",
+ correlationIdBytes = []
+ }).
+
+-record(command_message, {
+ parent = #async_message{},
+ operation = ?UNKNOWN_OPERATION
+ }).
View
27 temp/server/record_utils.erl
@@ -56,9 +56,34 @@ set(Obj, parameters, Value) when is_record(Obj, remoting_message) ->
{ok, NewObj, {parameters, Value}};
set(Obj, RpcMessageProperty, Value) when is_record(Obj, remoting_message) and is_atom(RpcMessageProperty) ->
{ok, NewRpcMessage, _} = set(Obj#remoting_message.parent, RpcMessageProperty, Value),
- set(Obj, parent, NewRpcMessage).
+ set(Obj, parent, NewRpcMessage);
+
+set(Obj, parent, Value) when is_record(Obj, async_message) and is_record(Value, abstract_message) ->
+ NewObj = Obj#async_message{parent = Value},
+ {ok, NewObj, {parent, Value}};
+set(Obj, correlationId, Value) when is_record(Obj, async_message) ->
+ NewObj = Obj#async_message{correlationId = Value},
+ {ok, NewObj, {correlationId, Value}};
+set(Obj, correlationIdBytes, Value) when is_record(Obj, async_message) ->
+ NewObj = Obj#async_message{correlationIdBytes = Value},
+ {ok, NewObj, {correlationIdBytes, Value}};
+set(Obj, AbstractMessageProperty, Value) when is_record(Obj, async_message) and is_atom(AbstractMessageProperty) ->
+ {ok, NewAbstractMessage, _} = set(Obj#async_message.parent, AbstractMessageProperty, Value),
+ set(Obj, parent, NewAbstractMessage);
+
+set(Obj, parent, Value) when is_record(Obj, command_message) and is_record(Value, async_message) ->
+ NewObj = Obj#command_message{parent = Value},
+ {ok, NewObj, {parent, Value}};
+set(Obj, operation, Value) when is_record(Obj, command_message) ->
+ NewObj = Obj#command_message{operation = Value},
+ {ok, NewObj, {operation, Value}};
+set(Obj, AsyncMessageProperty, Value) when is_record(Obj, command_message) and is_atom(AsyncMessageProperty) ->
+ {ok, NewAsyncMessage, _} = set(Obj#command_message.parent, AsyncMessageProperty, Value),
+ set(Obj, parent, NewAsyncMessage).
+
fc_to_record(?FC_REMOTINGMESSAGE) -> {ok, #remoting_message{}};
+fc_to_record(?FC_COMMANDMESSAGE) -> {ok, #command_message{}};
fc_to_record(_) -> {ok, undefined}.
%% Convert String to term, Str must be term-like string
View
50 temp/server/ref_table.erl
@@ -0,0 +1,50 @@
+-module(ref_table).
+-author("trung@mdkt.org").
+
+-compile(export_all).
+
+%% TODO make sure error handlings are in place
+
+%% delete all objects
+clear(TableName) ->
+ try ets:delete_all_objects(TableName) of
+ true ->
+ _ = ets:insert(TableName, {counter, 0}),
+ {ok}
+ catch
+ error:Error ->
+ {bad, Error}
+ end.
+
+%% Make sure the table exist, if not, create new one
+sure_exist(TableName) ->
+ case ets:info(TableName) of
+ undefined ->
+ ets:new(TableName, [named_table]),
+ _ = ets:insert(TableName, {counter, 0}),
+ {ok, created};
+ _ ->
+ {ok, exists}
+ end.
+
+%% wrapper of ets:insert, just make sure the table exists
+insert(TableName, Obj) ->
+ _ = sure_exist(TableName),
+ {ok, Count} = read(TableName, counter),
+ io:fwrite("Inserting into ~p - index: ~p - value: ~p ~n", [TableName, Count, Obj]),
+ _ = ets:insert(TableName, {Count, Obj}),
+ _ = ets:insert(TableName, {counter, Count+1}),
+ {ok, inserted, Count}.
+
+%% wrapper of ets:lookup
+read(TableName, Ref) ->
+%% io:fwrite("Read from ~p with index ~p got value ", [TableName, Ref]),
+ case ets:lookup(TableName, Ref) of
+ [] ->
+ {bad, {not_found, TableName, Ref}};
+ [{counter, Count}|_] ->
+ {ok, Count};
+ [{_Idx, Obj}|_] ->
+%% io:fwrite("~p~n", [Obj]),
+ {ok, Obj}
+ end.

0 comments on commit 0cc401d

Please sign in to comment.