|
| 1 | +unit HproseServer; |
| 2 | + |
| 3 | +{$I Hprose.inc} |
| 4 | + |
| 5 | +interface |
| 6 | + |
| 7 | +uses |
| 8 | + Classes, SysUtils, Variants, HproseCommon, HproseIO; |
| 9 | + |
| 10 | +type |
| 11 | + |
| 12 | + THproseServer = class; |
| 13 | + |
| 14 | + TResultMode = (rmNormal, rmSerialized, rmRaw, rmRawWithEndTag); |
| 15 | + TMethodType = (mtProc, mtFunc, mtProcArgs, mtFuncArgs); |
| 16 | + |
| 17 | + TInvokeFunction00 = procedure; |
| 18 | + TInvokeFunction01 = function: Variant; |
| 19 | + TInvokeFunction10 = procedure(Args: Variant); |
| 20 | + TInvokeFunction11 = function(Args: Variant): Variant; |
| 21 | + |
| 22 | + TInvokeMethod00 = procedure of object; |
| 23 | + TInvokeMethod01 = function: Variant of object; |
| 24 | + TInvokeMethod10 = procedure(Args: Variant) of object; |
| 25 | + TInvokeMethod11 = function(Args: Variant): Variant of object; |
| 26 | + |
| 27 | + TBeforeInvokeEvent = procedure(Name: string; Args: Variant; ByRef: Boolean) of object; |
| 28 | + TAfterInvokeEvent = procedure(Name: string; Args: Variant; ByRef: Boolean; Result: Variant) of object; |
| 29 | + |
| 30 | + TErrorEvent = procedure(Error: Exception) of object; |
| 31 | + |
| 32 | + THproseMethod = class |
| 33 | + private |
| 34 | + FMethod: TMethod; |
| 35 | + FMethodType: TMethodType; |
| 36 | + public |
| 37 | + constructor Create(Method: TMethod; MethodType: TMethodType); |
| 38 | + function Invoke(Args: Variant): Variant; |
| 39 | + end; |
| 40 | + |
| 41 | + THproseServer = class(TComponent) |
| 42 | + private |
| 43 | + FMethods: THashMap; |
| 44 | + FMethodNames: THashMap; |
| 45 | + FResultMode: THashMap; |
| 46 | + FDebug: Boolean; |
| 47 | + FOnBeforeInvoke: TBeforeInvokeEvent; |
| 48 | + FOnAfterInvoke: TAfterInvokeEvent; |
| 49 | + FOnSendError: TErrorEvent; |
| 50 | + procedure AddMethod(Method: TMethod; MethodType: TMethodType; AliasName: string; ResultMode: TResultMode);overload; |
| 51 | + protected |
| 52 | + procedure DoFunctionList(OutStream: TStream); |
| 53 | + procedure DoInvoke(InStream: TStream; OutStream: TStream); |
| 54 | + procedure HandleCommand(InStream: TStream; OutStream: TStream); |
| 55 | + public |
| 56 | + constructor Create(AOwner: TComponent); override; |
| 57 | + destructor Destroy; override; |
| 58 | + procedure AddFunction(Func: Pointer; MethodType: TMethodType; FuncName: string; ResultMode: TResultMode = rmNormal); |
| 59 | + procedure AddMethod(Cls: TClass; MethodName: string; MethodType: TMethodType; AliasName: string = ''; ResultMode: TResultMode = rmNormal); overload; |
| 60 | + procedure AddMethod(Obj: TObject; MethodName: string; MethodType: TMethodType; AliasName: string = ''; ResultMode: TResultMode = rmNormal); overload; |
| 61 | + published |
| 62 | + property DebugEnabled: Boolean read FDebug write FDebug default False; |
| 63 | + property OnBeforeInvoke: TBeforeInvokeEvent read FOnBeforeInvoke write FOnBeforeInvoke; |
| 64 | + property OnAfterInvoke: TAfterInvokeEvent read FOnAfterInvoke write FOnAfterInvoke; |
| 65 | + property OnSendError: TErrorEvent read FOnSendError write FOnSendError; |
| 66 | + end; |
| 67 | + |
| 68 | +implementation |
| 69 | + |
| 70 | +uses |
| 71 | + TypInfo; |
| 72 | + |
| 73 | +{ THproseMethod } |
| 74 | + |
| 75 | +constructor THproseMethod.Create(Method: TMethod; MethodType: TMethodType); |
| 76 | +begin |
| 77 | + FMethod := Method; |
| 78 | + FMethodType := MethodType; |
| 79 | +end; |
| 80 | + |
| 81 | +function THproseMethod.Invoke(Args: Variant): Variant; |
| 82 | +begin |
| 83 | + if FMethod.Data = nil then |
| 84 | + case FMethodType of |
| 85 | + mtProc: |
| 86 | + TInvokeFunction00(FMethod.Code)(); |
| 87 | + mtFunc: |
| 88 | + Result := TInvokeFunction01(FMethod.Code)(); |
| 89 | + mtProcArgs: |
| 90 | + TInvokeFunction10(FMethod.Code)(Args); |
| 91 | + mtFuncArgs: |
| 92 | + Result := TInvokeFunction11(FMethod.Code)(Args); |
| 93 | + end |
| 94 | + else |
| 95 | + case FMethodType of |
| 96 | + mtProc: |
| 97 | + TInvokeMethod00(FMethod)(); |
| 98 | + mtFunc: |
| 99 | + Result := TInvokeMethod01(FMethod)(); |
| 100 | + mtProcArgs: |
| 101 | + TInvokeMethod10(FMethod)(Args); |
| 102 | + mtFuncArgs: |
| 103 | + Result := TInvokeMethod11(FMethod)(Args); |
| 104 | + end; |
| 105 | +end; |
| 106 | + |
| 107 | +{ THproseServer } |
| 108 | + |
| 109 | +constructor THproseServer.Create(AOwner: TComponent); |
| 110 | +begin |
| 111 | + inherited Create(AOwner); |
| 112 | + FMethods := TCaseInsensitiveHashedMap.Create; |
| 113 | + FMethodNames := TCaseInsensitiveHashedMap.Create; |
| 114 | + FResultMode := TCaseInsensitiveHashedMap.Create; |
| 115 | +end; |
| 116 | + |
| 117 | +destructor THproseServer.Destroy; |
| 118 | +var |
| 119 | + Enum: IListEnumerator; |
| 120 | +begin |
| 121 | + Enum := FMethods.Values.GetEnumerator; |
| 122 | + while Enum.MoveNext do |
| 123 | + THproseMethod(Integer(Enum.Current)).Free; |
| 124 | + FMethods.Free; |
| 125 | + FMethodNames.Free; |
| 126 | + FResultMode.Free; |
| 127 | + inherited; |
| 128 | +end; |
| 129 | + |
| 130 | +procedure THproseServer.AddMethod(Method: TMethod; MethodType: TMethodType; |
| 131 | + AliasName: string; ResultMode: TResultMode); |
| 132 | +begin |
| 133 | + FMethods[AliasName] := Integer(THproseMethod.Create(Method, MethodType)); |
| 134 | + //FMethodNames[AliasName] := MethodName; |
| 135 | + FResultMode[AliasName] := ResultMode; |
| 136 | +end; |
| 137 | + |
| 138 | +procedure THproseServer.AddFunction(Func: Pointer; MethodType: TMethodType; |
| 139 | + FuncName: string; ResultMode: TResultMode); |
| 140 | +var |
| 141 | + Method: TMethod; |
| 142 | +begin |
| 143 | + if Func <> nil then |
| 144 | + begin |
| 145 | + Method.Code := Func; |
| 146 | + Method.Data := nil; |
| 147 | + AddMethod(Method, MethodType, FuncName, ResultMode); |
| 148 | + end; |
| 149 | +end; |
| 150 | + |
| 151 | +procedure THproseServer.AddMethod(Cls: TClass; MethodName: string; |
| 152 | + MethodType: TMethodType; AliasName: string; ResultMode: TResultMode); |
| 153 | +var |
| 154 | + Method: TMethod; |
| 155 | +begin |
| 156 | + Method.Code := Cls.MethodAddress(MethodName); |
| 157 | + if Method.Code <> nil then |
| 158 | + begin |
| 159 | + Method.Data := Cls; |
| 160 | + if AliasName = '' then |
| 161 | + AliasName := MethodName; |
| 162 | + AddMethod(Method, MethodType, AliasName, ResultMode); |
| 163 | + end; |
| 164 | + |
| 165 | +end; |
| 166 | + |
| 167 | +procedure THproseServer.AddMethod(Obj: TObject; MethodName: string; |
| 168 | + MethodType: TMethodType; AliasName: string; ResultMode: TResultMode); |
| 169 | +var |
| 170 | + Method: TMethod; |
| 171 | +begin |
| 172 | + Method.Code := Obj.MethodAddress(MethodName); |
| 173 | + if Method.Code <> nil then |
| 174 | + begin |
| 175 | + Method.Data := Obj; |
| 176 | + if AliasName = '' then |
| 177 | + AliasName := MethodName; |
| 178 | + AddMethod(Method, MethodType, AliasName, ResultMode); |
| 179 | + end; |
| 180 | +end; |
| 181 | + |
| 182 | +procedure THproseServer.DoFunctionList(OutStream: TStream); |
| 183 | +var |
| 184 | + Writer: THproseWriter; |
| 185 | +begin |
| 186 | + Writer := THproseWriter.Create(OutStream); |
| 187 | + try |
| 188 | + OutStream.Write(HproseTagFunctions, 1); |
| 189 | + Writer.Serialize(FMethodS.Keys); |
| 190 | + OutStream.Write(HproseTagEnd, 1); |
| 191 | + finally |
| 192 | + Writer.Free; |
| 193 | + end; |
| 194 | +end; |
| 195 | + |
| 196 | +procedure THproseServer.DoInvoke(InStream: TStream; OutStream: TStream); |
| 197 | +var |
| 198 | + Reader: THproseReader; |
| 199 | + Writer: THproseWriter; |
| 200 | + Tag: AnsiChar; |
| 201 | + MethodName: string; |
| 202 | + Method: THproseMethod; |
| 203 | + ResultMode: TResultMode; |
| 204 | + Args, Result: Variant; |
| 205 | + ByRef: Boolean; |
| 206 | +begin |
| 207 | + Reader := THproseReader.Create(InStream); |
| 208 | + Writer := THproseWriter.Create(OutStream); |
| 209 | + try |
| 210 | + repeat |
| 211 | + Reader.Reset; |
| 212 | + ByRef := False; |
| 213 | + MethodName := Reader.ReadString; |
| 214 | + Tag := Reader.CheckTags(HproseTagList + HproseTagEnd + HproseTagCall); |
| 215 | + if Tag = HproseTagList then |
| 216 | + begin |
| 217 | + Reader.Reset; |
| 218 | + Args := Reader.ReadList(varVariant, nil, False); |
| 219 | + Tag := Reader.CheckTags(HproseTagTrue + HproseTagEnd + HproseTagCall); |
| 220 | + if Tag = HproseTagTrue then |
| 221 | + begin |
| 222 | + ByRef := True; |
| 223 | + Tag := Reader.CheckTags(HproseTagEnd + HproseTagCall); |
| 224 | + end; |
| 225 | + end; |
| 226 | + if FMethods.ContainsKey(MethodName) then |
| 227 | + begin |
| 228 | + Method := THproseMethod(Integer(FMethods[MethodName])); |
| 229 | + ResultMode := TResultMode(FResultMode[MethodName]); |
| 230 | + if Assigned(FOnBeforeInvoke) then |
| 231 | + FOnBeforeInvoke(Name, Args, ByRef); |
| 232 | + Result := Method.Invoke(Args); |
| 233 | + if Assigned(FOnAfterInvoke) then |
| 234 | + FOnAfterInvoke(Name, Args, ByRef, Result); |
| 235 | + if ResultMode = rmRawWithEndTag then |
| 236 | + begin |
| 237 | + OutStream.Write(AnsiString(Result)[1], Length(AnsiString(Result))); |
| 238 | + Exit; |
| 239 | + end |
| 240 | + else if ResultMode = rmRaw then |
| 241 | + OutStream.Write(AnsiString(Result)[1], Length(AnsiString(Result))) |
| 242 | + else |
| 243 | + begin |
| 244 | + OutStream.Write(HproseTagResult, 1); |
| 245 | + if ResultMode = rmSerialized then |
| 246 | + OutStream.Write(AnsiString(Result)[1], Length(AnsiString(Result))) |
| 247 | + else |
| 248 | + begin |
| 249 | + Writer.Reset; |
| 250 | + Writer.Serialize(Result); |
| 251 | + end; |
| 252 | + if ByRef then |
| 253 | + begin |
| 254 | + OutStream.write(HproseTagArgument, 1); |
| 255 | + Writer.Reset; |
| 256 | + Writer.Serialize(Args); |
| 257 | + end; |
| 258 | + end; |
| 259 | + OutStream.Write(HproseTagEnd, 1); |
| 260 | + end |
| 261 | + else |
| 262 | + raise EHproseException.Create(Format('Can''''t find this function %s.', [MethodName])); |
| 263 | + until (Tag <> HproseTagCall); |
| 264 | + except |
| 265 | + On E: Exception do |
| 266 | + begin |
| 267 | + if Assigned(OnSendError) then |
| 268 | + OnSendError(E); |
| 269 | + OutStream.Write(HproseTagError, 1); |
| 270 | + if FDebug then |
| 271 | + Writer.WriteString(E.ToString, False) |
| 272 | + else |
| 273 | + Writer.WriteString(E.Message, False); |
| 274 | + OutStream.Write(HproseTagEnd, 1) |
| 275 | + end; |
| 276 | + end; |
| 277 | + Reader.Free; |
| 278 | + Writer.Free; |
| 279 | +end; |
| 280 | + |
| 281 | +procedure THproseServer.HandleCommand(InStream: TStream; OutStream: TStream); |
| 282 | +var |
| 283 | + Reader: THproseReader; |
| 284 | + Tag: AnsiChar; |
| 285 | +begin |
| 286 | + Reader := THproseReader.Create(InStream); |
| 287 | + Tag := Reader.CheckTags(HproseTagCall + HproseTagEnd); |
| 288 | + if Tag = HproseTagEnd then |
| 289 | + DoFunctionList(OutStream) |
| 290 | + else |
| 291 | + DoInvoke(InStream, OutStream); |
| 292 | + Reader.Free; |
| 293 | +end; |
| 294 | + |
| 295 | +end. |
| 296 | + |
0 commit comments