diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f288702..0000000 --- a/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README.md b/README.md deleted file mode 100644 index 632c840..0000000 --- a/README.md +++ /dev/null @@ -1,585 +0,0 @@ -origin 游戏服务器引擎简介 -================== - - -origin 是一个由 Go 语言(golang)编写的分布式开源游戏服务器引擎。origin适用于各类游戏服务器的开发,包括 H5(HTML5)游戏服务器。 - -origin 解决的问题: -* origin总体设计如go语言设计一样,总是尽可能的提供简洁和易用的模式,快速开发。 -* 能够根据业务需求快速并灵活的制定服务器架构。 -* 利用多核优势,将不同的service配置到不同的node,并能高效的协同工作。 -* 将整个引擎抽象三大对象,node,service,module。通过统一的组合模式管理游戏中各功能模块的关系。 -* 有丰富并健壮的工具库。 - -Hello world! ---------------- -下面我们来一步步的建立origin服务器,先下载[origin引擎](https://github.com/duanhf2012/origin "origin引擎"),或者使用如下命令: -```go -go get -v -u github.com/duanhf2012/origin -``` -于是下载到GOPATH环境目录中,在src中加入main.go,内容如下: -```go -package main - -import ( - "github.com/duanhf2012/origin/originnode" -) - -func main() { - node := originnode.NewOriginNode() - if node == nil { - return - } - - node.Init() - node.Start() -} -``` -一个origin服务器需要创建一个node对象,然后必需有Init和Start的流程。 - -origin引擎三大对象关系 ---------------- -* Node: 可以认为每一个Node代表着一个origin进程 -* Service:一个独立的服务可以认为是一个大的功能模块,他是Node的子集,创建完成并安装Node对象中。服务可以支持外部RPC和HTTP接口对外功能。 -* Module: 这是origin最小对象单元,强烈建议所有的业务模块都划分成各个小的Module组合。Module可以建立树状关系。Service本身也是Module的类型。 - -origin集群核心配置文件config/cluser.json如下: ---------------- -``` -{ - "SubNet": [{ - "Remark": "Manual,Full,Auto", - "SubNetMode": "Full", - "SubNetName": "SubNet1", - "PublicServiceList": ["logiclog"], - "NodeList": [{ - "NodeID": 1, - "NodeName": "N_Node1", - "ServiceList": [ - "HttpServerService", - "SubNet1_Service", - "SubNet1_Service1" - ], - "ClusterNode":["SubNet2.N_Node1","N_Node2"] - }, - { - "NodeID": 2, - "NodeName": "N_Node2", - "ServiceList": [ - "SubNet1_Service2" - ], - "ClusterNode":[] - } - ] - }, - - - { - "Remark": "Manual,Full,Auto", - "SubNetMode": "Full", - "SubNetName": "SubNet2", - "PublicServiceList": ["logiclog"], - "NodeList": [{ - "NodeID": 3, - "NodeName": "N_Node1", - "ServiceList": [ - "SubNet2_Service1" - ], - "ClusterNode":["URQ.N_Node1"] - }, - { - "NodeID": 4, - "NodeName": "N_Node4", - "ServiceList": [ - "SubNet2_Service2" - ], - "ClusterNode":[] - } - ] - } - ] -} -``` -origin集群配置以子网的模式配置,在每个子网下配置多个Node服务器,子网在应对复杂的系统时可以应用到各个子系统,方便每个子系统的隔离。 - -origin所有的结点与服务通过配置进行关联,配置文件分为两大配置结点: -* SubNet:配置子网,以上配置中包括子网名为SubNet1与SubNet2,每个子网包含多个Node结点。 - * SubNetMode:子网模式,Manual手动模式,Full通过配置全自动连接集群模式(推荐模式),Auto自动模式 - * SubNetName:子网名称 - * PublicServiceList:用于公共服务配置,所有的结点默认会加载该服务列表 - * SubNetMode:子网集群模式, - * NodeList:Node所有的列表 - * NodeId: Node编号,用于标识唯一的进程id - * NodeName: Node名称,用于区分Node结点功能。例如,可以是GameServer - * ServiceList:结点中允许开启的服务列表 - * ClusterNode:将与列表中的Node产生集群关系。允许访问这些结点中所有的服务。允许集群其他子网结点,例如:URQ.N_Node1 - -origin集群核心配置文件config/nodeconfig.json如下: ---------------- -``` -{ - "Public": { - "LogLevel": 1, - "HttpPort": 9400, - "WSPort": 9500, - - "CAFile": [{ - "CertFile": "", - "KeyFile": "" - }, - { - "CertFile": "", - "KeyFile": "" - } - ], - - "Environment": "FS_Dev_LFY", - "IsListenLog": 1, - "IsSendErrorMail": 0 - }, - "NodeList": [{ - "NodeID": 1, - "NodeAddr": "127.0.0.1:8081", - "LogLevel": 1, - "HttpPort": 7001, - "WSPort": 7000, - "CertFile": "", - "KeyFile": "" - }, - { - "NodeID": 2, - "NodeAddr": "127.0.0.1:8082" - }, - { - "NodeID": 3, - "NodeAddr": "127.0.0.1:8083" - }, - { - "NodeID": 4, - "NodeAddr": "127.0.0.1:8084" - } - ] -} -``` -针对cluster.json中NodeId在该文件中配置具体环境的信息 -* Public:公共服务配置 - * LogLevel:日志等级 1:DEBUG 2:INFO 3:WARN 4:ERROR 5:FATAL。 - * HttpPort:当Node需要提供http服务时,安装HttpServerService后将使用该监听端口。 - * WSPort:当Node需要提供Websocket服务时,安装HttpServerService后将使用该监听端口。 - * CAFile:证书配置文件,支持多个。 -* NodeList: - * NodeID:结点ID,在cluster.json中所有的Node都需要在该文件中配置。 - * NodeAddr:监听RPC地址与端口。 - * 其他:该配置可以继承Public中所有的配置,可以在其中自定义LogLevel,HttpPort等。 - - - -origin第一个服务: ---------------- -我们准备的NodeId为1的结点下新建两个服务,分别是CTestService1与CTestService2。 -* config/cluster.json内容如下 -``` -{ - "SubNet": [{ - "Remark": "Manual,Full,Auto", - "SubNetMode": "Full", - "SubNetName": "SubNet1", - "PublicServiceList": ["logiclog"], - "NodeList": [{ - "NodeID": 1, - "NodeName": "N_Node1", - "ServiceList": [ - "TestService1", - "TestService2" - ], - "ClusterNode":[] - }, - { - "NodeID": 2, - "NodeName": "N_Node2", - "ServiceList": [ - "TestService3" - ], - "ClusterNode":[] - } - ] - } - ] -} -``` -* config/nodeconfig.json内容如下 -``` -{ - "Public": { - "LogLevel": 1, - "HttpPort": 9400, - "WSPort": 9500, - "Environment": "Test", - "IsListenLog": 1, - "IsSendErrorMail": 0 - }, - - "NodeList": [{ - "NodeID": 1, - "NodeAddr": "127.0.0.1:8081" - }, - { - "NodeID": 2, - "NodeAddr": "127.0.0.1:8082" - } - ] -} -``` - - -* main.go运行代码 - -```go -package main - -import ( - "github.com/duanhf2012/origin/originnode" -) - -func main() { - - node := originnode.NewOriginNode() - if node == nil { - return - } - - node.Init() - node.Start() -} - -``` - -* TestService1.go运行代码 -```go -package main - -import ( - "fmt" - - "github.com/duanhf2012/origin/cluster" - "github.com/duanhf2012/origin/originnode" - "github.com/duanhf2012/origin/service" -) - -type TestService1 struct { - service.BaseService -} - -func init() { - originnode.InitService(&TestService1{}) -} - -//OnInit ... -func (ws *TestService1) OnInit() error { - - return nil -} - -//OnRun ... -func (ws *TestService1) OnRun() bool { - var i InputData - var j int - i.A1 = 3 - i.A2 = 4 - err := cluster.Call("TestService2.RPC_Add", &i, &j) - if err == nil { - fmt.Printf(" TestService2.RPC_Add is %d\n", j) - } - - err = cluster.Call("TestService3.RPC_Multi", &i, &j) - if err == nil { - fmt.Printf(" TestService2.RPC_Multi is %d\n", j) - } - - return false -} - -``` - - - -* TestService2.go运行代码 -```go -package main - -import ( - "github.com/duanhf2012/origin/originnode" - "github.com/duanhf2012/origin/service" -) - -type InputData struct { - A1 int - A2 int -} - -type TestService2 struct { - service.BaseService -} - -func init() { - originnode.InitService(&TestService2{}) -} - -//OnInit ... -func (ws *TestService2) OnInit() error { - - return nil -} - -//OnRun ... -func (ws *TestService2) OnRun() bool { - return false -} - -//服务要对外的接口规划如下: -//RPC_MethodName(arg *DataType1, ret *DataType2) error -//如果不符合规范,在加载服务时,该函数将不会被映射,其他服务将不允能调用。 -func (slf *TestService2) RPC_Add(arg *InputData, ret *int) error { - - *ret = arg.A1 + arg.A2 - - return nil -} -``` - -* TestService3.go运行代码 -```go -package main - -import ( - "github.com/duanhf2012/origin/originnode" - "github.com/duanhf2012/origin/service" -) - -type TestService3 struct { - service.BaseService -} - -func init() { - originnode.InitService(&TestService3{}) -} - -//OnInit ... -func (ws *TestService3) OnInit() error { - return nil -} - -//OnRun ... -func (ws *TestService3) OnRun() bool { - return false -} - -func (slf *TestService3) RPC_Multi(arg *InputData, ret *int) error { - *ret = arg.A1 * arg.A2 - return nil -} -``` - - - -通过以下命令运行: -``` -OriginServer.exe NodeId=2 -OriginServer.exe NodeId=1 -``` -其中NodeId=1的进程输出结果: -``` -TestService2.RPC_Add is 7 -TestService2.RPC_Multi is 12 -``` -通过日志可以确认,在Node启动时分别驱动Service的OnInit,OnRun,OnEndRun,上面的日志中TestService1.OnRun会被调用, -因为在OnRun的返回是false,所以OnRun只会进入一次。当返回true时,会重复循环进入OnRun。如果你不需要OnRun可以不定义OnRun函数。 -示例中,我们分别调用了本进程的TestService2服务中的RPC_Add的RPC接口,以及NodeId为2进程中服务为TestService3的接口RPC_Multi。 - -origin服务间通信: ---------------- -origin是通过rpc的方式互相调用,当前结点只能访问cluster.json中有配置ClusterNode的结点或本地结点中所有的服务接口,下面我们来用实际例子来说明,如下代码所示: -``` -package main - -import ( - "Server/service/websockservice" - "fmt" - "time" - - "github.com/duanhf2012/origin/cluster" - - "github.com/duanhf2012/origin/sysservice" - - "github.com/duanhf2012/origin/originnode" - "github.com/duanhf2012/origin/service" -) - -type CTestService1 struct { - service.BaseService -} - -//输入参数,注意变量名首字母大写 -type InputData struct { - A1 int - A2 int -} - -func (slf *CTestService1) OnRun() bool { - var ret int - input := InputData{100, 11} - - //调用服务名.接口名称,传入传出参数必需为地址,符合RPC_Add接口规范 - //以下可以采用其他,注意如果在服务名前加入下划线"_"表示访问本node中的服务 - //_servicename.methodname - //servicename.methodname - err := cluster.Call("CTestService2.RPC_Add", &input, &ret) - fmt.Print(err, "\n", ret) - - return false -} - -type CTestService2 struct { - service.BaseService -} - -//注意格式一定要RPC_开头,函数第一个参数为输入参数,第二个为输出参数,只允许指针类型 -//返回值必需为error,如果不满足格式,装载服务时将被会忽略。 -func (slf *CTestService2) RPC_Add(arg *InputData, ret *int) error { - *ret = arg.A1 + arg.A2 - return nil -} - -func main() { - node := originnode.NewOriginNode() - if node == nil { - return - } - //也可以通过以下方式安装服务CTestService1与CTestService2 - node.SetupService(&CTestService1{}, &CTestService2{}) - node.Init() - node.Start() -} - -``` -输入结果为: -``` - -111 -``` -cluster.Call只允许调用一个结点中的服务,如果服务在多个结点中,是不允许的。注意,Call方式是阻塞模式,只有当被调服务响应时才返回,或者超过最大超时时间。如果不想阻塞,可以采用Go方式调用。例如:cluster.Go(true,"CTestService2.RPC_Send", &input) -第一个参数代码是否广播,如果调用的服务接口在多个Node中存在,都将被调用。还可以向指定的NodeId调用,例如: -``` -func (slf *CCluster) CallNode(nodeid int, servicemethod string, args interface{}, reply interface{}) error -func (slf *CCluster) GoNode(nodeid int, args interface{}, servicemethod string) error -``` -在实际使用时,注意抽象service,只有合理的划分service,origin是以service为最小集群单元放到不同的node中,以达到动态移动service功能到不同的node进程中。 - -origin中Module使用: ---------------- -module在origin引擎中是最小的对象单元,service本质上也是一个复杂的module。它同样有着以下方法: -``` -OnInit() error //Module初始化时调用 -OnRun() bool //Module运行时调用 -OnEndRun() -``` -在使用规则上和service是一样的,因为本质上是一样的对象。看以下简单示例: -``` -package main - -import ( - "fmt" - "time" - - "github.com/duanhf2012/origin/originnode" - "github.com/duanhf2012/origin/service" -) - -type CTestService1 struct { - service.BaseService -} - -type CTestModule1 struct { - service.BaseModule -} - -func (slf *CTestModule1) OnInit() error { - fmt.Printf("CTestModule1::OnInit\n") - return nil -} - -func (slf *CTestModule1) OnRun() bool { - fmt.Printf("CTestModule1::OnRun\n") - time.Sleep(time.Second * 1) - return true -} - -func (slf *CTestModule1) OnEndRun() { - fmt.Printf("CTestModule1::OnEndRun\n") -} - -func (slf *CTestModule1) Add(a int, b int) int { - return a + b -} - -func (slf *CTestService1) OnRun() bool { - testmodule := CTestModule1{} - - //可以设置自定义id - //testmodule.SetModuleId(PLAYERID) - - //添加module到slf对象中 - moduleId := slf.AddModule(&testmodule) - - //获取module对象 - pModule := slf.GetModuleById(moduleId) - //转换为CTestModule1类型 - ret := pModule.(*CTestModule1).Add(3, 4) - fmt.Printf("ret is %d\n", ret) - - time.Sleep(time.Second * 4) - //释放module - slf.ReleaseModule(moduleId) - - return false -} - -func main() { - node := originnode.NewOriginNode() - if node == nil { - return - } - node.SetupService(&CTestService1{}) - node.Init() - node.Start() -} -``` -执行结果如下: -``` -ret is 7 -CTestModule1::OnInit -CTestModule1::OnRun -CTestModule1::OnRun -CTestModule1::OnRun -CTestModule1::OnRun -CTestModule1::OnEndRun -``` -以上创建新的Module加入到当前服务对象中,可以获取释放动作。同样CTestModule1模块也可以加入子模块,使用方法一样。以上日志每秒钟CTestModule1::OnRun打印一次,4秒后ReleaseModule,对象被释放,执行CTestModule1::OnEndRun。 - -origin中其他重要服务: ---------------- -* github.com\duanhf2012\origin\sysservice集成了系统常用的服务 - * httpserverervice:提供对外的http服务 - * wsserverservice :websocket服务 - * logservice :日志服务 - -以上服务请参照github.com\duanhf2012\origin\Test目录使用方法 -* github.com\duanhf2012\origin\sysmodule集成了系统常用的Module - * DBModule: mysql数据库操作模块,支持异步调用 - * RedisModule: Redis操作模块,支持异步调用 - * LogModule: 日志模块,支持区分日志等级 - * HttpClientPoolModule:http客户端模块 - - - - diff --git a/Test/.vscode/launch.json b/Test/.vscode/launch.json deleted file mode 100644 index 87a1481..0000000 --- a/Test/.vscode/launch.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - - "configurations": [ - { - "name": "N_All", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceRoot}/main.go", - "env": { - "GOPATH":"${workspaceRoot}/../../../../../" - }, - "args": ["NodeId=1"], - "output": "./OriginServer.exe" - } - ] -} \ No newline at end of file diff --git a/Test/.vscode/settings.json b/Test/.vscode/settings.json deleted file mode 100644 index ef5cde8..0000000 --- a/Test/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "go.gopath": "${workspaceRoot}/../../../../../" -} diff --git a/Test/build.bat b/Test/build.bat deleted file mode 100644 index d55ef7c..0000000 --- a/Test/build.bat +++ /dev/null @@ -1,4 +0,0 @@ -SET CGO_ENABLED=0 -SET GOOS=linux -SET GOARCH=amd64 -go build -v \ No newline at end of file diff --git a/Test/config/cluster.json b/Test/config/cluster.json deleted file mode 100644 index 329fab7..0000000 --- a/Test/config/cluster.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "SubNet": [{ - "Remark": "Manual,Full,Auto", - "SubNetMode": "Full", - "SubNetName": "SubNet1", - "PublicServiceList": ["logiclog"], - "NodeList": [{ - "NodeID": 1, - "NodeName": "N_Node1", - "ServiceList": [ - "HttpServerService", - "SubNet1_Service", - "TcpSocketPbService", - "ls" - ], - "ClusterNode":["SubNet2.N_Node1","N_Node2"] - }, - { - "NodeID": 2, - "NodeName": "N_Node2", - "ServiceList": [ - "SubNet1_Service2" - ], - "ClusterNode":[] - } - ] - }, - - - { - "Remark": "Manual,Full,Auto", - "SubNetMode": "Full", - "SubNetName": "SubNet2", - "PublicServiceList": ["logiclog"], - "NodeList": [{ - "NodeID": 3, - "NodeName": "N_Node1", - "ServiceList": [ - "SubNet2_Service1" - ], - "ClusterNode":["URQ.N_Node1"] - } - ] - } - ] -} - - - - - - - - - diff --git a/Test/config/nodeconfig.json b/Test/config/nodeconfig.json deleted file mode 100644 index 35a3724..0000000 --- a/Test/config/nodeconfig.json +++ /dev/null @@ -1,50 +0,0 @@ -{ -"Public":{ - "LogLevel":1, - "HttpPort":9400, - "WSPort":9401, - "ListenPort":9412, - "CAFile":[ - { - "CertFile":"", - "KeyFile":"" - }, - { - "CertFile":"", - "KeyFile":"" - } - ], - - "Environment":"FS_Dev_LFY", - "IsListenLog":1, - "IsSendErrorMail":0 -}, - -"NodeList":[ -{ - "NodeID":1, - "NodeAddr": "127.0.0.1:8181", - "LogLevel":1, - "HttpPort":7001, - "WSPort":7000, - "CertFile":"", - "KeyFile":"" -}, -{ - "NodeID":2, - "NodeAddr": "127.0.0.1:8082" -} -, -{ - "NodeID":3, - "NodeAddr": "127.0.0.1:8083" -} -, -{ - "NodeID":40, - "NodeAddr": "127.0.0.1:8084", - "LogLevel":1 -} -] - -} \ No newline at end of file diff --git a/Test/logicservice/SubNet1_Service.go b/Test/logicservice/SubNet1_Service.go deleted file mode 100644 index 7dc01fe..0000000 --- a/Test/logicservice/SubNet1_Service.go +++ /dev/null @@ -1,122 +0,0 @@ -package logicservice - -import ( - "fmt" - "github.com/duanhf2012/origin/Test/msgpb" - "github.com/duanhf2012/origin/cluster" - "github.com/duanhf2012/origin/network" - "github.com/duanhf2012/origin/sysservice" - "github.com/golang/protobuf/proto" - "time" - - "github.com/duanhf2012/origin/originnode" - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysservice/originhttp" -) - -type SubNet1_Service struct { - service.BaseService -} - -func init() { - originnode.InitService(&SubNet1_Service{}) -} - -//OnInit ... -func (ws *SubNet1_Service) OnInit() error { - sysservice.GetTcpSocketPbService("ls").RegConnectEvent(ws.ConnEventHandler) - sysservice.GetTcpSocketPbService("ls").RegDisconnectEvent(ws.DisconnEventHandler) - sysservice.GetTcpSocketPbService("ls").RegExceptMessage(ws.ExceptMessage) - sysservice.GetTcpSocketPbService("ls").RegMessage(110, &msgpb.Test{}, ws.MessageHandler) - - /* - sysservice.GetTcpSocketPbService("lc").RegConnectEvent(ws.ConnEventHandler2) - sysservice.GetTcpSocketPbService("lc").RegDisconnectEvent(ws.DisconnEventHandler2) - sysservice.GetTcpSocketPbService("lc").RegExceptMessage(ws.ExceptMessage2) - sysservice.GetTcpSocketPbService("lc").RegMessage(110, &msgpb.Test{}, ws.MessageHandler2) -*/ - - - //originhttp.Post(" / aaa/bb/ :user/:pass/", ws.HTTP_UserIntegralInfo) - - originhttp.Get(" /aaa/bbb", ws.HTTP_UserIntegralInfo) - originhttp.SetStaticResource(originhttp.METHOD_GET, "/file/", "d:\\") - - return nil -} - -type InputData struct { - A1 int - A2 int -} - -//OnRun ... -func (ws *SubNet1_Service) OnRun() bool { - time.Sleep(time.Second * 10) - var cli network.TcpSocketClient - cli.Connect("127.0.0.1:9402") - test := msgpb.Test{} - test.AssistCount = proto.Int32(343) - - cli.SendMsg(110, &test) - cli.SendMsg(110, &test) - - var a InputData - var rs int - a.A1 = 3 - a.A2 = 4 - cluster.Call("SubNet1_Service2.RPC_Sub",&a,&rs) - fmt.Print(rs) - return false -} - -func (ws *SubNet1_Service) MessageHandler(clientid uint64, msgtype uint16, msg proto.Message) { - fmt.Print("recv:",clientid, ":", msg,"\n") - sysservice.GetTcpSocketPbService("ls").SendMsg(clientid,msgtype,msg) -/*test core dump - var a map[int]int - a[33] = 3 - fmt.Print(a[44]) - */ -} - -func (ws *SubNet1_Service) ConnEventHandler(clientid uint64) { - fmt.Print("connected..",clientid,"\n") -} - -func (ws *SubNet1_Service) DisconnEventHandler(clientid uint64) { - fmt.Print("disconnected..",clientid,"\n") -} - -func (ws *SubNet1_Service) ExceptMessage(clientid uint64, pPack *network.MsgBasePack, err error) { - fmt.Print("except..",clientid,",",pPack,"\n") -} - - - -/////////////////////////// - -func (ws *SubNet1_Service) MessageHandler2(clientid uint64, msgtype uint16, msg proto.Message) { - fmt.Print("recv:",clientid, ":", msg,"\n") - //pClient.SendMsg(msgtype,msg) - sysservice.GetTcpSocketPbService("ls").SendMsg(clientid,msgtype,msg) -} - -func (ws *SubNet1_Service) ConnEventHandler2(clientid uint64) { - fmt.Print("connected..",clientid,"\n") -} - -func (ws *SubNet1_Service) DisconnEventHandler2(clientid uint64) { - fmt.Print("disconnected..",clientid,"\n") -} - -func (ws *SubNet1_Service) ExceptMessage2(clientid uint64, pPack *network.MsgBasePack, err error) { - fmt.Print("except..",clientid,",",pPack,"\n") -} - - -func (slf *SubNet1_Service) HTTP_UserIntegralInfo(request *originhttp.HttpRequest, resp *originhttp.HttpRespone) error { - ret, ok := request.Query("a") - fmt.Print(ret, ok) - return nil -} \ No newline at end of file diff --git a/Test/main.go b/Test/main.go deleted file mode 100644 index 5290f40..0000000 --- a/Test/main.go +++ /dev/null @@ -1,56 +0,0 @@ -package main - -import ( - _ "github.com/duanhf2012/origin/Test/logicservice" - "github.com/duanhf2012/origin/cluster" - "github.com/duanhf2012/origin/network" - "github.com/duanhf2012/origin/originnode" - "github.com/duanhf2012/origin/sysservice" - "github.com/duanhf2012/origin/sysservice/originhttp" - "time" -) - - -type TcpSocketServerReciver struct { - -} - -func (slf *TcpSocketServerReciver) OnConnected(pClient *network.SClient){ - -} - -func (slf *TcpSocketServerReciver) OnDisconnect(pClient *network.SClient){ - -} - - - -func main() { - - node := originnode.NewOriginNode() - if node == nil { - return - } - - //打开Module死循环监控 - node.EnableMonitorModule(time.Minute*5) - originhttp.SetStaticResource(originhttp.METHOD_GET,"/img/","d:/") - nodeCfg, _ := cluster.ReadNodeConfig("./config/nodeconfig.json", cluster.GetNodeId()) - httpserver := originhttp.NewHttpServerService(nodeCfg.HttpPort) // http服务 - for _, ca := range nodeCfg.CAFile { - httpserver.SetHttps(ca.CertFile, ca.KeyFile) - } - - pTcpService := sysservice.NewTcpSocketPbService(":9412") - pTcpService.SetServiceName("ls") -/* - pTcpService2 := sysservice.NewTcpSocketPbService(":9005") - pTcpService2.SetServiceName("lc") -*/ - httpserver.SetPrintRequestTime(true) - - node.SetupService(httpserver,pTcpService) - - node.Init() - node.Start() -} diff --git a/Test/msgpb/gen.bat b/Test/msgpb/gen.bat deleted file mode 100644 index 546eec0..0000000 --- a/Test/msgpb/gen.bat +++ /dev/null @@ -1 +0,0 @@ -protoc --go_out=. test.proto \ No newline at end of file diff --git a/Test/msgpb/test.pb.go b/Test/msgpb/test.pb.go deleted file mode 100644 index 2fb5f59..0000000 --- a/Test/msgpb/test.pb.go +++ /dev/null @@ -1,132 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: test.proto - -package msgpb - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -//* -// @brief base_score_info -type Test struct { - WinCount *int32 `protobuf:"varint,1,opt,name=win_count,json=winCount" json:"win_count,omitempty"` - LoseCount *int32 `protobuf:"varint,2,opt,name=lose_count,json=loseCount" json:"lose_count,omitempty"` - ExceptionCount *int32 `protobuf:"varint,3,opt,name=exception_count,json=exceptionCount" json:"exception_count,omitempty"` - KillCount *int32 `protobuf:"varint,4,opt,name=kill_count,json=killCount" json:"kill_count,omitempty"` - DeathCount *int32 `protobuf:"varint,5,opt,name=death_count,json=deathCount" json:"death_count,omitempty"` - AssistCount *int32 `protobuf:"varint,6,opt,name=assist_count,json=assistCount" json:"assist_count,omitempty"` - Rating *int64 `protobuf:"varint,7,opt,name=rating" json:"rating,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Test) Reset() { *m = Test{} } -func (m *Test) String() string { return proto.CompactTextString(m) } -func (*Test) ProtoMessage() {} -func (*Test) Descriptor() ([]byte, []int) { - return fileDescriptor_c161fcfdc0c3ff1e, []int{0} -} - -func (m *Test) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Test.Unmarshal(m, b) -} -func (m *Test) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Test.Marshal(b, m, deterministic) -} -func (m *Test) XXX_Merge(src proto.Message) { - xxx_messageInfo_Test.Merge(m, src) -} -func (m *Test) XXX_Size() int { - return xxx_messageInfo_Test.Size(m) -} -func (m *Test) XXX_DiscardUnknown() { - xxx_messageInfo_Test.DiscardUnknown(m) -} - -var xxx_messageInfo_Test proto.InternalMessageInfo - -func (m *Test) GetWinCount() int32 { - if m != nil && m.WinCount != nil { - return *m.WinCount - } - return 0 -} - -func (m *Test) GetLoseCount() int32 { - if m != nil && m.LoseCount != nil { - return *m.LoseCount - } - return 0 -} - -func (m *Test) GetExceptionCount() int32 { - if m != nil && m.ExceptionCount != nil { - return *m.ExceptionCount - } - return 0 -} - -func (m *Test) GetKillCount() int32 { - if m != nil && m.KillCount != nil { - return *m.KillCount - } - return 0 -} - -func (m *Test) GetDeathCount() int32 { - if m != nil && m.DeathCount != nil { - return *m.DeathCount - } - return 0 -} - -func (m *Test) GetAssistCount() int32 { - if m != nil && m.AssistCount != nil { - return *m.AssistCount - } - return 0 -} - -func (m *Test) GetRating() int64 { - if m != nil && m.Rating != nil { - return *m.Rating - } - return 0 -} - -func init() { - proto.RegisterType((*Test)(nil), "msgpb.test") -} - -func init() { proto.RegisterFile("test.proto", fileDescriptor_c161fcfdc0c3ff1e) } - -var fileDescriptor_c161fcfdc0c3ff1e = []byte{ - // 178 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x8c, 0x5d, 0x0a, 0x82, 0x40, - 0x14, 0x46, 0x99, 0xfc, 0x29, 0xaf, 0x51, 0xe0, 0x43, 0x08, 0x11, 0x59, 0x2f, 0xf9, 0xd4, 0x26, - 0xda, 0x81, 0x1b, 0x08, 0xb3, 0xc1, 0x86, 0x6c, 0x46, 0xbc, 0x37, 0x6c, 0xc5, 0xad, 0x23, 0x66, - 0xee, 0xe4, 0xe3, 0x77, 0xce, 0xe1, 0x03, 0x20, 0x89, 0x74, 0xee, 0x07, 0x43, 0x26, 0x8b, 0x5e, - 0xd8, 0xf6, 0xb7, 0xe3, 0x57, 0x40, 0x68, 0x69, 0xb6, 0x85, 0x64, 0x54, 0xfa, 0xda, 0x98, 0xb7, - 0xa6, 0x5c, 0x14, 0xa2, 0x8c, 0xaa, 0xc5, 0xa8, 0xf4, 0xc5, 0xee, 0x6c, 0x07, 0xd0, 0x19, 0x94, - 0xde, 0xce, 0x9c, 0x4d, 0x2c, 0x61, 0x7d, 0x82, 0xb5, 0xfc, 0x34, 0xb2, 0x27, 0x65, 0xfe, 0x0f, - 0x81, 0x6b, 0x56, 0x13, 0x9e, 0x7e, 0x9e, 0xaa, 0xeb, 0x7c, 0x13, 0xf2, 0x8f, 0x25, 0xac, 0xf7, - 0x90, 0xde, 0x65, 0x4d, 0x0f, 0xef, 0x23, 0xe7, 0xc1, 0x21, 0x0e, 0x0e, 0xb0, 0xac, 0x11, 0x15, - 0x92, 0x2f, 0x62, 0x57, 0xa4, 0xcc, 0x38, 0xd9, 0x40, 0x3c, 0xd4, 0xa4, 0x74, 0x9b, 0xcf, 0x0b, - 0x51, 0x06, 0x95, 0x5f, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x46, 0xa0, 0x89, 0x59, 0xfc, 0x00, - 0x00, 0x00, -} diff --git a/Test/msgpb/test.proto b/Test/msgpb/test.proto deleted file mode 100644 index 001411d..0000000 --- a/Test/msgpb/test.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto2"; - -package msgpb; - - -/** - * @brief base_score_info - */ -message test{ - optional int32 win_count = 1; // 玩家胜局局数 - optional int32 lose_count = 2; // 玩家负局局数 - optional int32 exception_count = 3; // 玩家异常局局数 - optional int32 kill_count = 4; // 总人头数 - optional int32 death_count = 5; // 总死亡数 - optional int32 assist_count = 6; // 总总助攻数 - optional int64 rating = 7; // 评价积分 -} - diff --git a/Test/workspace.code-workspace b/Test/workspace.code-workspace deleted file mode 100644 index cd39b81..0000000 --- a/Test/workspace.code-workspace +++ /dev/null @@ -1,13 +0,0 @@ -{ - "folders": [ - { - "path": "." - }, - { - "path": "D:\\GOPATH\\src\\github.com" - } - ], - "settings": { - "http.systemCertificates": false - } -} \ No newline at end of file diff --git a/Test2/Helloworld/.vscode/launch.json b/Test2/Helloworld/.vscode/launch.json deleted file mode 100644 index cf043fa..0000000 --- a/Test2/Helloworld/.vscode/launch.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - - "configurations": [ - { - "name": "N_All", - "type": "go", - "request": "launch", - "mode": "auto", - "program": "${workspaceRoot}/main.go", - "env": { - "GOPATH":"${workspaceRoot}/../../../../../../" - }, - "args": ["NodeId=1"], - "output": "./OriginServer.exe" - } - ] -} \ No newline at end of file diff --git a/Test2/Helloworld/.vscode/settings.json b/Test2/Helloworld/.vscode/settings.json deleted file mode 100644 index ef5cde8..0000000 --- a/Test2/Helloworld/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "go.gopath": "${workspaceRoot}/../../../../../" -} diff --git a/Test2/Helloworld/build.bat b/Test2/Helloworld/build.bat deleted file mode 100644 index d55ef7c..0000000 --- a/Test2/Helloworld/build.bat +++ /dev/null @@ -1,4 +0,0 @@ -SET CGO_ENABLED=0 -SET GOOS=linux -SET GOARCH=amd64 -go build -v \ No newline at end of file diff --git a/Test2/Helloworld/config/cluster.json b/Test2/Helloworld/config/cluster.json deleted file mode 100644 index 3980558..0000000 --- a/Test2/Helloworld/config/cluster.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "SubNet": [{ - "Remark": "Manual,Full,Auto", - "SubNetMode": "Full", - "SubNetName": "SubNet1", - "PublicServiceList": ["logiclog"], - "NodeList": [{ - "NodeID": 1, - "NodeName": "N_Node1", - "ServiceList": [ - "TestService1", - "TestService2", - "HttpServerService" - ], - "ClusterNode":[] - }, - { - "NodeID": 2, - "NodeName": "N_Node2", - "ServiceList": [ - "TestService3" - ], - "ClusterNode":[] - } - ] - } - ] -} - - - - - - - - - diff --git a/Test2/Helloworld/config/nodeconfig.json b/Test2/Helloworld/config/nodeconfig.json deleted file mode 100644 index a09df0a..0000000 --- a/Test2/Helloworld/config/nodeconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "Public": { - "LogLevel": 1, - "HttpPort": 9400, - "WSPort": 9500, - "Environment": "Test", - "IsListenLog": 1, - "IsSendErrorMail": 0 - }, - - "NodeList": [{ - "NodeID": 1, - "NodeAddr": "127.0.0.1:8081" - }, - { - "NodeID": 2, - "NodeAddr": "127.0.0.1:8082" - } - ] -} \ No newline at end of file diff --git a/Test2/Helloworld/main.go b/Test2/Helloworld/main.go deleted file mode 100644 index 8873e98..0000000 --- a/Test2/Helloworld/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "github.com/duanhf2012/origin/originnode" -) - -func main() { - - node := originnode.NewOriginNode() - if node == nil { - return - } - - node.Init() - node.Start() -} diff --git a/Test2/Helloworld/workspace.code-workspace b/Test2/Helloworld/workspace.code-workspace deleted file mode 100644 index 1283249..0000000 --- a/Test2/Helloworld/workspace.code-workspace +++ /dev/null @@ -1,10 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "http.systemCertificates": false - } -} \ No newline at end of file diff --git a/_config.yml b/_config.yml deleted file mode 100644 index b849713..0000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-leap-day \ No newline at end of file diff --git a/cluster/cluster.go b/cluster/cluster.go index b8c3aea..cf4a077 100644 --- a/cluster/cluster.go +++ b/cluster/cluster.go @@ -1,723 +1,135 @@ package cluster import ( - "errors" "fmt" - "math/rand" - "net" - "os" - "sort" + "github.com/duanhf2012/originnet/log" + "github.com/duanhf2012/originnet/rpc" + "github.com/duanhf2012/originnet/service" "strings" - "time" - - "github.com/duanhf2012/origin/rpc" - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysmodule" ) -type RpcClient struct { - nodeid int - pclient *rpc.Client - serverAddr string +var configdir = "./config/" + +type SubNet struct { + NodeList []NodeInfo } -func (slf *RpcClient) IsConnected() bool { - return (slf.pclient != nil) && (slf.pclient.IsClosed() == false) +type NodeInfo struct { + NodeId int + ListenAddr string + NodeName string + ServiceList []string } -type CCluster struct { - port int - cfg *ClusterConfig - nodeclient map[int]*RpcClient - - reader net.Conn - writer net.Conn - - LocalRpcClient *rpc.Client - innerLocalServiceList map[string]bool +type NodeRpcInfo struct { + nodeinfo NodeInfo + client *rpc.Client } -func (slf *CCluster) ReadNodeInfo(nodeid int) error { - mapNodeData, err := ReadAllNodeConfig("./config/nodeconfig.json") + + +var cluster Cluster + +type Cluster struct { + localsubnet SubNet //本子网 + mapSubNetInfo map[string] SubNet //子网名称,子网信息 + + mapSubNetNodeInfo map[string]map[int]NodeInfo //map[子网名称]map[NodeId]NodeInfo + localSubNetMapNode map[int]NodeInfo //本子网内 map[NodeId]NodeInfo + localSubNetMapService map[string][]NodeInfo //本子网内所有ServiceName对应的结点列表 + localNodeMapService map[string]interface{} //本Node支持的服务 + localNodeInfo NodeInfo + + localNodeServiceCfg map[string]interface{} //map[servicename]数据 + + mapRpc map[int] NodeRpcInfo//nodeid + + rpcServer rpc.Server +} + + +func SetConfigDir(cfgdir string){ + configdir = cfgdir +} + +func (slf *Cluster) Init(currentNodeId int) error{ + //1.初始化配置 + err := slf.InitCfg(currentNodeId) if err != nil { return err } - slf.cfg, err = ReadCfg("./config/cluster.json", nodeid, mapNodeData) - if err != nil { - return err + slf.rpcServer.Init(slf) + + //2.建议rpc连接 + slf.mapRpc = map[int] NodeRpcInfo{} + for _,nodeinfo := range slf.localSubNetMapNode { + rpcinfo := NodeRpcInfo{} + rpcinfo.nodeinfo = nodeinfo + rpcinfo.client = &rpc.Client{} + if nodeinfo.NodeId == currentNodeId { + rpcinfo.client.Connect("localhost") + //rpcinfo.client.Connect(nodeinfo.ListenAddr) + }else{ + rpcinfo.client.Connect(nodeinfo.ListenAddr) + } + slf.mapRpc[nodeinfo.NodeId] = rpcinfo } return nil } -func (slf *CCluster) GetClusterClient(id int) *rpc.Client { - if id == GetNodeId() { - return slf.LocalRpcClient +func (slf *Cluster) FindRpcHandler(servicename string) rpc.IRpcHandler { + pService := service.GetService(servicename) + if pService == nil { + return nil } - v, ok := slf.nodeclient[id] + return pService.GetRpcHandler() +} + +func (slf *Cluster) Start() { + slf.rpcServer.Start(slf.localNodeInfo.ListenAddr) +} + +func GetCluster() *Cluster{ + return &cluster +} + +func (slf *Cluster) GetRpcClient(nodeid int) *rpc.Client { + c,ok := slf.mapRpc[nodeid] if ok == false { return nil } - return v.pclient + return c.client } -func (slf *CCluster) GetBindUrl() string { - return slf.cfg.currentNode.ServerAddr -} +func GetRpcClient(serviceMethod string) ([]*rpc.Client,error) { + serviceAndMethod := strings.Split(serviceMethod,".") + if len(serviceAndMethod)!=2 { + return nil,fmt.Errorf("servicemethod param %s is error!",serviceMethod) + } -func (slf *CCluster) AcceptRpc(tpcListen *net.TCPListener) error { - for { - conn, err := tpcListen.Accept() - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "tpcListen.Accept error:%v", err) - return err + //1.找到对应的rpcnodeid + var rpcClientList []*rpc.Client + nodeidList := GetCluster().GetNodeIdByService(serviceAndMethod[0]) + if len(nodeidList) ==0 { + return rpcClientList,fmt.Errorf("Cannot Find %s nodeid",serviceMethod) + } + + for _,nodeid:= range nodeidList { + pClient := GetCluster().GetRpcClient(nodeid) + if pClient==nil { + log.Error("Cannot connect node id %d",nodeid) + continue } - go rpc.ServeConn(conn) + rpcClientList = append(rpcClientList,pClient) } - return nil + return rpcClientList,nil } -func (slf *CCluster) ListenService() error { - - bindStr := slf.GetBindUrl() - parts := strings.Split(bindStr, ":") - if len(parts) < 2 { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "ListenService address %s is error.", bindStr) - os.Exit(1) - } - bindStr = "0.0.0.0:" + parts[1] - - // - tcpaddr, err := net.ResolveTCPAddr("tcp4", bindStr) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "ResolveTCPAddr error:%v", err) - os.Exit(1) - return err - } - - tcplisten, err2 := net.ListenTCP("tcp", tcpaddr) - if err2 != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "ListenTCP error:%v", err2) - os.Exit(1) - return err2 - } - go slf.AcceptRpc(tcplisten) - slf.ReSetLocalRpcClient() - return nil -} - -func (slf *CCluster) ReSetLocalRpcClient() { - slf.reader, slf.writer = net.Pipe() - go rpc.ServeConn(slf.reader) - slf.LocalRpcClient = rpc.NewClient(slf.writer,true) -} - -type CPing struct { - TimeStamp int64 -} - -type CPong struct { - TimeStamp int64 -} - -func (slf *CPing) Ping(ping *CPing, pong *CPong) error { - pong.TimeStamp = ping.TimeStamp - return nil -} - -func (slf *CCluster) GetClusterMode() string { - return slf.cfg.GetClusterMode() -} - -func (slf *CCluster) ConnService() error { - ping := CPing{0} - pong := CPong{0} - rpc.RegisterName("CPing", "", &ping) - - //连接集群服务器 - for _, nodeList := range slf.cfg.mapClusterNodeService { - for _, node := range nodeList { - if node.NodeID == slf.cfg.currentNode.NodeID { - continue - } - slf.nodeclient[node.NodeID] = &RpcClient{node.NodeID, nil, node.ServerAddr} - } - } - - //判断集群模式 - - for { - for _, rpcClient := range slf.nodeclient { - - //连接状态发送ping - if rpcClient.IsConnected() == true { - ping.TimeStamp = 0 - err := rpcClient.pclient.Call("CPing.Ping", &ping, &pong) - - if err != nil { - rpcClient.pclient.Close() - rpcClient.pclient = nil - continue - } - - continue - } - - //非连接状态重新连接 - if rpcClient.pclient != nil { - rpcClient.pclient.Close() - rpcClient.pclient = nil - } - - client, err := rpc.Dial("tcp", rpcClient.serverAddr) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_WARN, "Connect nodeid:%d,address:%s fail", rpcClient.nodeid, rpcClient.serverAddr) - continue - } - service.GetLogger().Printf(sysmodule.LEVER_INFO, "Connect nodeid:%d,address:%s succ", rpcClient.nodeid, rpcClient.serverAddr) - - v, _ := slf.nodeclient[rpcClient.nodeid] - v.pclient = client - } - - if slf.LocalRpcClient.IsClosed() { - slf.ReSetLocalRpcClient() - } - time.Sleep(time.Second * 4) - } - - return nil -} - -func (slf *CCluster) Init(currentNodeid int) error { - slf.nodeclient = make(map[int]*RpcClient) - - return slf.ReadNodeInfo(currentNodeid) -} - -func (slf *CCluster) Start() error { - service.InstanceServiceMgr().FetchService(slf.OnFetchService) - - //监听服务 - slf.ListenService() - - //集群 - go slf.ConnService() - - return nil -} - -//servicename.methodname -//_servicename.methodname -func (slf *CCluster) Call(NodeServiceMethod string, args interface{}, reply interface{}) error { - var callServiceName string - var serviceName string - nodeidList := slf.GetNodeList(NodeServiceMethod, &callServiceName, &serviceName) - if len(nodeidList) > 1 || len(nodeidList) < 1 { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s) find nodes count %d is error.", NodeServiceMethod, len(nodeidList)) - return fmt.Errorf("CCluster.Call(%s) find nodes count %d is error.", NodeServiceMethod, len(nodeidList)) - } - - nodeid := nodeidList[0] - if nodeid == GetNodeId() { - //判断服务是否已经完成初始化 - iService := service.InstanceServiceMgr().FindService(serviceName) - if iService == nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s): NodeId %d cannot find service.", NodeServiceMethod, nodeid) - return fmt.Errorf("CCluster.Call(%s): NodeId %d cannot find service..", NodeServiceMethod, nodeid) - } - if iService.IsInit() == false { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s): NodeId %d is not init.", NodeServiceMethod, nodeid) - return fmt.Errorf("CCluster.Call(%s): NodeId %d is not init.", NodeServiceMethod, nodeid) - } - return slf.LocalRpcClient.Call(callServiceName, args, reply) - } else { - pclient := slf.GetClusterClient(nodeid) - if pclient == nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s): NodeId %d is not find.", NodeServiceMethod, nodeid) - return fmt.Errorf("CCluster.Call(%s): NodeId %d is not find.", NodeServiceMethod, nodeid) - } - err := pclient.Call(callServiceName, args, reply) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s) is fail:%v.", callServiceName, err) - } - return err - } - - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s) fail.", NodeServiceMethod) - return fmt.Errorf("CCluster.Call(%s) fail.", NodeServiceMethod) -} - -func (slf *CCluster) GetNodeList(NodeServiceMethod string, rpcServerMethod *string, rpcServiceName *string) []int { - var nodename string - var servicename string - var methodname string - var nodeidList []int - - parts := strings.Split(NodeServiceMethod, ".") - if len(parts) == 2 { - servicename = parts[0] - methodname = parts[1] - } else if len(parts) == 3 { - nodename = parts[0] - servicename = parts[1] - methodname = parts[2] - } else { - return nodeidList - } - - if nodename == "" { - nodeidList = make([]int, 0) - if servicename[:1] == "_" { - servicename = servicename[1:] - nodeidList = append(nodeidList, GetNodeId()) - } else { - nodeidList = slf.cfg.GetIdByService(servicename, "") - } - } else { - nodeidList = slf.GetIdByNodeService(nodename, servicename) - } - - if rpcServiceName != nil { - *rpcServiceName = servicename - } - - if rpcServerMethod != nil { - *rpcServerMethod = servicename + "." + methodname - } - - return nodeidList -} - -//GetNodeIdByServiceName 根据服务名查找nodeid servicename服务名 bOnline是否需要查找在线服务 -func (slf *CCluster) GetNodeIdByServiceName(servicename string, bOnline bool) []int { - nodeIDList := slf.cfg.GetIdByService(servicename, "") - - if bOnline { - ret := make([]int, 0, len(nodeIDList)) - for _, nodeid := range nodeIDList { - if slf.CheckNodeIsConnectedByID(nodeid) { - ret = append(ret, nodeid) - } - } - return ret - } - - return nodeIDList -} - -//根据Service获取负载均衡信息 -//负载均衡的策略是从配置获取所有配置了该服务的NodeId 并按NodeId排序 每个node负责处理数组index所在的那一部分 -func (slf *CCluster) GetBalancingInfo(currentNodeId int, servicename string, inSubNet bool) (*BalancingInfo, error) { - subNetName := "" - if inSubNet { - if node, ok := slf.cfg.mapIdNode[currentNodeId]; ok { - subNetName = node.SubNetName - } else { - return nil, fmt.Errorf("[cluster.GetBalancingInfo] cannot find node %d", currentNodeId) - } - } - lst := slf.cfg.GetIdByService(servicename, subNetName) - // if len(lst) <= 0 { - // return nil, fmt.Errorf("[cluster.GetBalancingInfo] cannot find service %s in any node", servicename) - // } - sort.Ints(lst) - ret := &BalancingInfo{ - NodeId: currentNodeId, - ServiceName: servicename, - TotalNum: len(lst), - MyIndex: -1, - NodeList: lst, - } - if _, ok := slf.cfg.mapIdNode[currentNodeId]; ok { - for i, v := range lst { - if v == currentNodeId { - ret.MyIndex = i - break - } - } - } - return ret, nil -} - -func (slf *CCluster) CheckNodeIsConnectedByID(nodeid int) bool { - if nodeid == GetNodeId() { - return true - } - - pclient := slf.GetRpcClientByNodeId(nodeid) - if pclient == nil { - return false - } - - return pclient.IsConnected() -} - -func (slf *CCluster) GetRpcClientByNodeId(nodeid int) *RpcClient { - - pclient, ok := slf.nodeclient[nodeid] - if ok == false { - return nil - } - - return pclient -} - -func (slf *CCluster) Go(bCast bool, NodeServiceMethod string, args interface{}, queueModle bool) error { - return slf.goImpl(bCast, NodeServiceMethod, args, queueModle, true) -} - - - -func (slf *CCluster) goImpl(bCast bool, NodeServiceMethod string, args interface{}, queueModle bool, log bool) error { - var callServiceName string - var serviceName string - nodeidList := slf.GetNodeList(NodeServiceMethod, &callServiceName, &serviceName) - if len(nodeidList) < 1 { - err := fmt.Errorf("CCluster.Go(%s) not find nodes.", NodeServiceMethod) - if log { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, err.Error()) - } - return err - } - - if bCast == false && len(nodeidList) > 1 { - return fmt.Errorf("CCluster.Go(%s) find more nodes", NodeServiceMethod) - } - - for _, nodeid := range nodeidList { - if nodeid == GetNodeId() { - iService := service.InstanceServiceMgr().FindService(serviceName) - if iService == nil { - return fmt.Errorf("CCluster.Go(%s) cannot find service %s", NodeServiceMethod, serviceName) - } - if iService.IsInit() == false { - err := fmt.Errorf("CCluster.Call(%s): NodeId %d is not init.", NodeServiceMethod, nodeid) - if log { - service.GetLogger().Printf(sysmodule.LEVER_WARN, err.Error()) - } - return err - } - - replyCall := slf.LocalRpcClient.Go(callServiceName, args, nil, nil, queueModle) - if replyCall.Error != nil { - err := fmt.Errorf("CCluster.Go(%s) fail:%v.", NodeServiceMethod, replyCall.Error) - if log { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, err.Error()) - } else { - return err - } - } - } else { - pclient := slf.GetClusterClient(nodeid) - if pclient == nil { - err := fmt.Errorf("CCluster.Go(%s) NodeId %d not find client", NodeServiceMethod, nodeid) - if log { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, err.Error()) - } - return err - } - replyCall := pclient.Go(callServiceName, args, nil, nil, queueModle) - if replyCall.Error != nil { - err := fmt.Errorf("CCluster.Go(%s) fail:%v.", NodeServiceMethod, replyCall.Error) - if log { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, err.Error()) - } - return err - } - } - } - - return nil -} - -func (slf *CCluster) CallNode(nodeid int, servicemethod string, args interface{}, reply interface{}) error { - pclient := slf.GetClusterClient(nodeid) - if pclient == nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.CallNode(%d,%s) NodeId not find client", nodeid, servicemethod) - return fmt.Errorf("Call: NodeId %d is not find.", nodeid) - } - - err := pclient.Call(servicemethod, args, reply) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.CallNode(%d,%s) fail:%v", nodeid, servicemethod, err) - } - - return err -} - -func (slf *CCluster) GoNode(nodeid int, args interface{}, servicemethod string, queueModle bool) error { - pclient := slf.GetClusterClient(nodeid) - if pclient == nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.GoNode(%d,%s) NodeId not find client", nodeid, servicemethod) - return fmt.Errorf("CCluster.GoNode(%d,%s) NodeId not find client", nodeid, servicemethod) - } - - replyCall := pclient.Go(servicemethod, args, nil, nil, queueModle) - if replyCall.Error != nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.GoNode(%d,%s) fail:%v", nodeid, servicemethod, replyCall.Error) - } - - return replyCall.Error - -} - -func (ws *CCluster) OnFetchService(iservice service.IService) error { - rpc.RegisterName(iservice.GetServiceName(), "RPC_", iservice) - return nil -} - -func (slf *CCluster) CallRandomService(NodeServiceMethod string, args interface{}, reply interface{}) error { - var servicename string - parts := strings.Split(NodeServiceMethod, ".") - if len(parts) == 2 { - servicename = parts[0] - } else { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.CallRandomService(%s) method err", NodeServiceMethod) - return fmt.Errorf("CCluster.GoNode(%s) NodeId method err", NodeServiceMethod) - } - - nodeList := slf.GetNodeIdByServiceName(servicename, true) - if len(nodeList) < 1 { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.CallRandomService(%s) no node is online", NodeServiceMethod) - return fmt.Errorf("CCluster.GoNode(%s) no node is online", NodeServiceMethod) - } - - nodeIndex := rand.Intn(len(nodeList)) - nodeID := nodeList[nodeIndex] - - return slf.CallNode(nodeID, NodeServiceMethod, args, reply) -} - -func (slf *CCluster) GoRandomService(NodeServiceMethod string, args interface{}, queueModle bool) error { - var servicename string - parts := strings.Split(NodeServiceMethod, ".") - if len(parts) == 2 { - servicename = parts[0] - } else { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.CallRandomService(%s) method err", NodeServiceMethod) - return fmt.Errorf("CCluster.GoNode(%s) NodeId method err", NodeServiceMethod) - } - - nodeList := slf.GetNodeIdByServiceName(servicename, true) - if len(nodeList) < 1 { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.CallRandomService(%s) no node is online", NodeServiceMethod) - return fmt.Errorf("CCluster.GoNode(%s) no node is online", NodeServiceMethod) - } - - nodeIndex := rand.Intn(len(nodeList)) - nodeID := nodeList[nodeIndex] - - return slf.GoNode(nodeID, args, NodeServiceMethod, queueModle) -} - -//向远程服务器调用 -//Node.servicename.methodname -//servicename.methodname -func Call(NodeServiceMethod string, args interface{}, reply interface{}) error { - return InstanceClusterMgr().Call(NodeServiceMethod, args, reply) -} - -func (slf *CCluster) CallEx(NodeServiceMethod string, args interface{}, reply interface{}) *RpcCallResult { - return slf.rawcall(NodeServiceMethod, args, reply, false) -} - -type RpcCallResult struct { - chanRet chan *rpc.Call - err error - rets *rpc.Call -} - -func (slf *RpcCallResult) Make() { - slf.chanRet = make(chan *rpc.Call, 1) - slf.rets = nil -} - -func (slf *RpcCallResult) WaitReturn(waittm time.Duration) error { - if slf.chanRet == nil { - return errors.New("cannot make rpccallresult") - } - - if waittm <= 0 { - select { - case ret := <-slf.chanRet: - return ret.Error - } - } else { - // - select { - case ret := <-slf.chanRet: - return ret.Error - case <-time.After(waittm): - return errors.New("is time out") - } - } - - return errors.New("unknow error.") -} - -func (slf *CCluster) rawcall(NodeServiceMethod string, args interface{}, reply interface{}, queueModle bool) *RpcCallResult { - var rpcRet RpcCallResult - rpcRet.Make() - - var callServiceName string - var serviceName string - nodeidList := slf.GetNodeList(NodeServiceMethod, &callServiceName, &serviceName) - if len(nodeidList) > 1 || len(nodeidList) < 1 { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s) find nodes count %d is error.", NodeServiceMethod, len(nodeidList)) - rpcRet.err = fmt.Errorf("CCluster.Call(%s) find nodes count %d is error.", NodeServiceMethod, len(nodeidList)) - return &rpcRet - } - - nodeid := nodeidList[0] - if nodeid == GetNodeId() { - //判断服务是否已经完成初始化 - iService := service.InstanceServiceMgr().FindService(serviceName) - if iService == nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s): NodeId %d cannot find service.", NodeServiceMethod, nodeid) - rpcRet.err = fmt.Errorf("CCluster.Call(%s): NodeId %d cannot find service..", NodeServiceMethod, nodeid) - return &rpcRet - } - - if iService.IsInit() == false { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s): NodeId %d is not init.", NodeServiceMethod, nodeid) - rpcRet.err = fmt.Errorf("CCluster.Call(%s): NodeId %d is not init.", NodeServiceMethod, nodeid) - return &rpcRet - } - - rpcRet.rets = slf.LocalRpcClient.Go(callServiceName, args, reply, rpcRet.chanRet, queueModle) - return &rpcRet - } - - pclient := slf.GetClusterClient(nodeid) - if pclient == nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "CCluster.Call(%s): NodeId %d is not find.", NodeServiceMethod, nodeid) - rpcRet.err = fmt.Errorf("CCluster.Call(%s): NodeId %d is not find.", NodeServiceMethod, nodeid) - return &rpcRet - } - - rpcRet.rets = pclient.Go(callServiceName, args, reply, rpcRet.chanRet, queueModle) - - return &rpcRet - -} - -func CallEx(NodeServiceMethod string, args interface{}, reply interface{}) *RpcCallResult { - return InstanceClusterMgr().rawcall(NodeServiceMethod, args, reply, false) -} - -func CallNode(NodeId int, servicemethod string, args interface{}, reply interface{}) error { - return InstanceClusterMgr().CallNode(NodeId, servicemethod, args, reply) -} - -func GoNode(NodeId int, servicemethod string, args interface{}) error { - return InstanceClusterMgr().GoNode(NodeId, args, servicemethod, false) -} - -func Go(NodeServiceMethod string, args interface{}) error { - return InstanceClusterMgr().Go(false, NodeServiceMethod, args, false) -} - -func CastGo(NodeServiceMethod string, args interface{}) error { - return InstanceClusterMgr().Go(true, NodeServiceMethod, args, false) -} - -func GoNodeQueue(NodeId int, servicemethod string, args interface{}) error { - return InstanceClusterMgr().GoNode(NodeId, args, servicemethod, true) -} - -func GoQueue(NodeServiceMethod string, args interface{}) error { - return InstanceClusterMgr().Go(false, NodeServiceMethod, args, true) -} - -//在GoQueue的基础上增加是否写日志参数 -func GoQueueEx(NodeServiceMethod string, args interface{}, log bool) error { - return InstanceClusterMgr().goImpl(false, NodeServiceMethod, args, true, log) -} - -func CastGoQueue(NodeServiceMethod string, args interface{}) error { - return InstanceClusterMgr().Go(true, NodeServiceMethod, args, true) -} - -//GetNodeIdByServiceName 根据服务名查找nodeid serviceName服务名 bOnline是否需要查找在线服务 -func GetNodeIdByServiceName(serviceName string, bOnline bool) []int { - return InstanceClusterMgr().GetNodeIdByServiceName(serviceName, bOnline) -} - -//获取服务的负载均衡信息 -//负载均衡的策略是从配置获取所有配置了该服务的NodeId 并按NodeId排序 每个node负责处理数组index所在的那一部分 -func GetBalancingInfo(currentNodeId int, servicename string, inSubNet bool) (*BalancingInfo, error) { - return InstanceClusterMgr().GetBalancingInfo(currentNodeId, servicename, inSubNet) -} - -//随机选择在线的node发送 -func CallRandomService(NodeServiceMethod string, args interface{}, reply interface{}) error { - return InstanceClusterMgr().CallRandomService(NodeServiceMethod, args, reply) -} -func GoRandomService(NodeServiceMethod string, args interface{}) error { - return InstanceClusterMgr().GoRandomService(NodeServiceMethod, args, false) -} -func GoRandomServiceQueue(NodeServiceMethod string, args interface{}) error { - return InstanceClusterMgr().GoRandomService(NodeServiceMethod, args, true) -} - -var _self *CCluster - -func InstanceClusterMgr() *CCluster { - if _self == nil { - _self = new(CCluster) - _self.innerLocalServiceList = make(map[string]bool) - return _self - } - return _self -} - -func (slf *CCluster) GetIdByNodeService(NodeName string, serviceName string) []int { - return slf.cfg.GetIdByNodeService(NodeName, serviceName) -} - -func (slf *CCluster) HasLocalService(serviceName string) bool { - _, ok := slf.innerLocalServiceList[serviceName] - return slf.cfg.HasLocalService(serviceName) || ok -} - -func (slf *CCluster) HasInit(serviceName string) bool { - return slf.cfg.HasLocalService(serviceName) -} - -func GetNodeId() int { - return _self.cfg.currentNode.NodeID -} - -func (slf *CCluster) AddLocalService(iservice service.IService) { - servicename := fmt.Sprintf("%T", iservice) - parts := strings.Split(servicename, ".") - if len(parts) != 2 { - service.GetLogger().Printf(service.LEVER_ERROR, "BaseService.Init: service name is error: %q", servicename) - } - - servicename = parts[1] - slf.innerLocalServiceList[servicename] = true -} - -func GetNodeName(nodeid int) string { - return _self.cfg.GetNodeNameByNodeId(nodeid) -} - -func DynamicCall(address string, serviceMethod string, args interface{}, reply interface{}) error { - rpcClient, err := rpc.DialTimeOut("tcp", address, time.Second*1) - if err != nil { - return err - } - defer rpcClient.Close() - err = rpcClient.Call(serviceMethod, args, reply) - if err != nil { - return err - } - - return nil -} +func GetRpcServer() *rpc.Server{ + return &cluster.rpcServer +} \ No newline at end of file diff --git a/cluster/config.go b/cluster/config.go deleted file mode 100644 index 9ab4561..0000000 --- a/cluster/config.go +++ /dev/null @@ -1,341 +0,0 @@ -package cluster - -import ( - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "strings" -) - -//负载均衡信息 -type BalancingInfo struct { - NodeId int //我的nodeId - ServiceName string //负载均衡的ServiceName - - TotalNum int //总共有多少个协同Node - MyIndex int //负责的index [0, TotalNum) - NodeList []int //所有协同的node列表 按NodeId升序排列 -} - -//判断hash后的Id是否命中我的NodeId -func (slf *BalancingInfo) Hit(hashId int) bool { - if hashId >= 0 && slf.TotalNum > 0 && slf.MyIndex >= 0 { - return hashId%slf.TotalNum == slf.MyIndex - } - return false -} - -//判断命中的NodeId,-1表示无法取得 -func (slf *BalancingInfo) GetHitNodeId(hashId int) int { - if hashId >= 0 && slf.TotalNum > 0 { - if idx := hashId % slf.TotalNum; idx >= 0 && idx < len(slf.NodeList) { - return slf.NodeList[idx] - } - } - return -1 -} - -type CNodeCfg struct { - NodeID int - NodeName string - ServiceList []string - ClusterNode []string -} - -type CNode struct { - SubNetName string - NodeID int - NodeName string //SubNetName.NodeName - ServerAddr string - ServiceList map[string]bool -} - -type SubNetNodeInfo struct { - SubNetMode string - SubNetName string - PublicServiceList []string - NodeList []CNodeCfg //配置列表 - - //mapClusterNodeService map[string][]CNode //map[nodename] []CNode - //mapClusterServiceNode map[string][]CNode //map[servicename] []CNode -} - -type ClusterConfig struct { - SubNet []SubNetNodeInfo - //CurrentSubNetIdx int - mapIdNode map[int]CNode - currentNode CNode //当前node - - mapClusterNodeService map[string][]CNode //map[nodename] []CNode - mapClusterServiceNode map[string][]CNode //map[servicename] []CNode -} - -func GenNodeName(subnetName string, nodename string) string { - parts := strings.Split(nodename, ".") - if len(parts) < 2 { - return subnetName + "." + nodename - } - - return nodename -} - -func AddCluster(clusterNodeNameList *[]string, nodename string) bool { - for _, n := range *clusterNodeNameList { - if n == nodename { - return false - } - } - - *clusterNodeNameList = append(*clusterNodeNameList, nodename) - return true -} - -func ReadCfg(path string, nodeid int, mapNodeData map[int]NodeData) (*ClusterConfig, error) { - clsCfg := &ClusterConfig{} - clsCfg.mapIdNode = map[int]CNode{} - clsCfg.mapClusterNodeService = make(map[string][]CNode, 1) - clsCfg.mapClusterServiceNode = make(map[string][]CNode, 1) - - //1.加载解析配置 - d, err := ioutil.ReadFile(path) - if err != nil { - fmt.Printf("Read File %s Error!", path) - return nil, err - } - - err = json.Unmarshal(d, clsCfg) - if err != nil { - fmt.Printf("Read File %s ,%s Error!", path, err) - return nil, err - } - - //存储所有的nodeid对应cnode信息 - var clusterNodeNameList []string - for _, c := range clsCfg.SubNet { - for _, v := range c.NodeList { - mapservice := make(map[string]bool, 1) - for _, s := range v.ServiceList { - mapservice[s] = true - } - nodeData, ok := mapNodeData[v.NodeID] - if ok == false { - return nil, errors.New(fmt.Sprintf("Cannot find node id %d in nodeconfig.json file!", v.NodeID)) - } - - node := CNode{c.SubNetName, v.NodeID, c.SubNetName + "." + v.NodeName, nodeData.NodeAddr, mapservice} - clsCfg.mapIdNode[v.NodeID] = node - - if v.NodeID == nodeid { - clsCfg.currentNode = node - for _, servicename := range c.PublicServiceList { - clsCfg.currentNode.ServiceList[servicename] = true - } - - for _, nodename := range v.ClusterNode { - AddCluster(&clusterNodeNameList, GenNodeName(c.SubNetName, nodename)) - } - AddCluster(&clusterNodeNameList, GenNodeName(c.SubNetName, v.NodeName)) - } - } - } - - if clsCfg.currentNode.NodeID == 0 { - return nil, errors.New(fmt.Sprintf("Cannot find NodeId %d in cluster.json!", nodeid)) - } - - //如果集群是FULL模式 - if strings.ToUpper(clsCfg.GetClusterMode()) == "FULL" { - for _, subnet := range clsCfg.SubNet { - if subnet.SubNetName == clsCfg.currentNode.SubNetName { - for _, nodes := range subnet.NodeList { - AddCluster(&clusterNodeNameList, GenNodeName(subnet.SubNetName, nodes.NodeName)) - } - } - } - } - - for _, clusternodename := range clusterNodeNameList { - for _, c := range clsCfg.SubNet { - for _, nodecfg := range c.NodeList { - if clusternodename != c.SubNetName+"."+nodecfg.NodeName { - continue - } - n, ok := clsCfg.mapIdNode[nodecfg.NodeID] - if ok == false { - return nil, errors.New(fmt.Sprintf("Cannot find NodeId %d in cluster.json!", nodecfg.NodeID)) - } - clsCfg.mapClusterNodeService[nodecfg.NodeName] = append(clsCfg.mapClusterNodeService[nodecfg.NodeName], n) - for _, sname := range nodecfg.ServiceList { - clsCfg.mapClusterServiceNode[sname] = append(clsCfg.mapClusterServiceNode[sname], n) - } - } - } - } - - return clsCfg, nil -} - -func (slf *ClusterConfig) GetIdByService(serviceName, subNetName string) []int { - var nodeidlist = []int{} - - nodeList, ok := slf.mapClusterServiceNode[serviceName] - if ok == true { - nodeidlist = make([]int, 0, len(nodeList)) - for _, v := range nodeList { - if subNetName == "" || subNetName == v.SubNetName { - nodeidlist = append(nodeidlist, v.NodeID) - } - } - } - - return nodeidlist -} - -func (slf *ClusterConfig) GetIdByNodeService(NodeName string, serviceName string) []int { - var nodeidlist []int - nodeidlist = make([]int, 0) - - if NodeName == slf.currentNode.NodeName { - nodeidlist = append(nodeidlist, slf.currentNode.NodeID) - } - - v, ok := slf.mapClusterNodeService[NodeName] - if ok == false { - return nodeidlist - } - - for _, n := range v { - _, ok = n.ServiceList[serviceName] - if ok == true { - nodeidlist = append(nodeidlist, n.NodeID) - } - } - - return nodeidlist -} - -func (slf *ClusterConfig) HasLocalService(serviceName string) bool { - _, ok := slf.currentNode.ServiceList[serviceName] - return ok == true -} - -func IsExistsNode(nodelist []CNode, pNode *CNode) bool { - for _, node := range nodelist { - if node.NodeID == pNode.NodeID { - return true - } - } - - return false -} - -func (slf *ClusterConfig) GetNodeNameByNodeId(nodeid int) string { - node, ok := slf.mapIdNode[nodeid] - if ok == false { - return "" - } - - return node.NodeName -} - -func (slf *ClusterConfig) GetClusterMode() string { - //SubNet []SubNetNodeInfo - for _, subnet := range slf.SubNet { - if subnet.SubNetName == slf.currentNode.SubNetName { - return subnet.SubNetMode - } - } - - return "" -} - -type CACfg struct { - CertFile string - KeyFile string -} - -//NodeConfig ... -type NodeData struct { - NodeID int - LogLevel uint - HttpPort uint16 - WSPort uint16 - ListenPort uint16 - NodeAddr string - CAFile []CACfg - - Environment string - IsListenLog int - IsSendErrorMail int -} - -type NodeConfig struct { - Public NodeData - NodeList []NodeData -} - -//ReadNodeConfig ... -func ReadAllNodeConfig(path string) (map[int]NodeData, error) { - c := &NodeConfig{} - d, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - err = json.Unmarshal(d, c) - if err != nil { - return nil, err - } - - var mapNodeData map[int]NodeData - mapNodeData = map[int]NodeData{} - - //data = c.Public - for _, v := range c.NodeList { - mapNodeData[v.NodeID] = v - } - - return mapNodeData, nil -} -func ReadNodeConfig(path string, nodeid int) (*NodeData, error) { - - c := &NodeConfig{} - d, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - err = json.Unmarshal(d, c) - if err != nil { - return nil, err - } - - var data NodeData - data = c.Public - for _, v := range c.NodeList { - if v.NodeID == nodeid { - data = v - if v.Environment == "" && c.Public.Environment != "" { - data.Environment = c.Public.Environment - } - if len(v.CAFile) == 0 && len(c.Public.CAFile) != 0 { - data.CAFile = c.Public.CAFile - } - - if v.HttpPort == 0 && c.Public.HttpPort != 0 { - data.HttpPort = c.Public.HttpPort - } - if v.WSPort == 0 && c.Public.WSPort != 0 { - data.WSPort = c.Public.WSPort - } - if v.LogLevel == 0 && c.Public.LogLevel != 0 { - data.LogLevel = c.Public.LogLevel - } - if v.IsListenLog == 0 && c.Public.IsListenLog != 0 { - data.IsListenLog = c.Public.IsListenLog - } - break - } - } - - return &data, nil -} diff --git a/cluster/parsecfg.go b/cluster/parsecfg.go new file mode 100644 index 0000000..0c82a2c --- /dev/null +++ b/cluster/parsecfg.go @@ -0,0 +1,192 @@ +package cluster + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "strings" +) + +func (slf *Cluster) ReadClusterConfig(filepath string) (*SubNet,error) { + c := &SubNet{} + d, err := ioutil.ReadFile(filepath) + if err != nil { + return nil, err + } + err = json.Unmarshal(d, c) + if err != nil { + return nil, err + } + + return c,nil +} + + +func (slf *Cluster) ReadServiceConfig(filepath string) (map[string]interface{},error) { + c := map[string]interface{}{} + + d, err := ioutil.ReadFile(filepath) + if err != nil { + return nil, err + } + err = json.Unmarshal(d, &c) + if err != nil { + return nil, err + } + + return c,nil + +} + +func (slf *Cluster) ReadAllSubNetConfig() error { + clusterCfgPath :=strings.TrimRight(configdir,"/") +"/cluster" + fileInfoList,err := ioutil.ReadDir(clusterCfgPath) + if err != nil { + return err + } + slf.mapSubNetInfo =map[string] SubNet{} + for _,f := range fileInfoList{ + if f.IsDir() == true { + subnetinfo,err:=slf.ReadClusterConfig(strings.TrimRight(strings.TrimRight(clusterCfgPath,"/"),"\\")+"/"+f.Name()+"/"+"cluster.json") + if err != nil { + return err + } + slf.mapSubNetInfo[f.Name()] = *subnetinfo + } + } + + + return nil +} + +func (slf *Cluster) ReadLocalSubNetServiceConfig(subnet string) error { + clusterCfgPath :=strings.TrimRight(configdir,"/") +"/cluster" + fileInfoList,err := ioutil.ReadDir(clusterCfgPath) + if err != nil { + return err + } + slf.mapSubNetInfo =map[string] SubNet{} + for _,f := range fileInfoList{ + if f.IsDir() == true && f.Name()==subnet{ //同一子网 + localNodeServiceCfg,err:=slf.ReadServiceConfig(strings.TrimRight(strings.TrimRight(clusterCfgPath,"/"),"\\")+"/"+f.Name()+"/"+"service.json") + if err != nil { + return err + } + slf.localNodeServiceCfg =localNodeServiceCfg + } + } + + return nil +} + + + +func (slf *Cluster) InitCfg(currentNodeId int) error{ + //mapSubNetInfo := map[string] SubNet{} //子网名称,子网信息 + mapSubNetNodeInfo := map[string]map[int]NodeInfo{} //map[子网名称]map[NodeId]NodeInfo + localSubNetMapNode := map[int]NodeInfo{} //本子网内 map[NodeId]NodeInfo + localSubNetMapService := map[string][]NodeInfo{} //本子网内所有ServiceName对应的结点列表 + localNodeMapService := map[string]interface{}{} //本Node支持的服务 + localNodeInfo := NodeInfo{} + + + err := slf.ReadAllSubNetConfig() + + //分析配置 + var localSubnetName string + for subnetName,subnetInfo := range slf.mapSubNetInfo { + for _,nodeinfo := range subnetInfo.NodeList { + //装载slf.mapNodeInfo + _,ok := mapSubNetNodeInfo[subnetName] + if ok == false { + mapnodeInfo := make(map[int]NodeInfo,1) + mapnodeInfo[nodeinfo.NodeId] = nodeinfo + mapSubNetNodeInfo[subnetName] = mapnodeInfo + }else{ + mapSubNetNodeInfo[subnetName][nodeinfo.NodeId] = nodeinfo + } + + //判断本进程的子网 + if nodeinfo.NodeId == currentNodeId { + localSubnetName = subnetName + } + } + } + + + //装载 + subnet,ok := slf.mapSubNetInfo[localSubnetName] + if ok == false { + return fmt.Errorf("NodeId %d not in any subnet",currentNodeId) + } + + for _,nodeinfo := range subnet.NodeList { + localSubNetMapNode[nodeinfo.NodeId] = nodeinfo + + //装载本Node进程所有的服务 + if nodeinfo.NodeId == currentNodeId { + for _,s := range nodeinfo.ServiceList { + servicename := s + if strings.Index(s,"_") == 0 { + servicename = s[1:] + } + localNodeMapService[servicename] = nil + } + localNodeInfo = nodeinfo + } + + for _,s := range nodeinfo.ServiceList { + //以_打头的,表示只在本机进程,不对整个子网开发 + if strings.Index(s,"_") == 0 { + continue + } + + if _,ok := localSubNetMapService[s];ok== true{ + localSubNetMapService[s] = []NodeInfo{} + } + localSubNetMapService[s] = append(localSubNetMapService[s],nodeinfo) + } + } + if localNodeInfo.NodeId == 0 { + return fmt.Errorf("Canoot find NodeId %d not in any config file.",currentNodeId) + } + + + slf.mapSubNetNodeInfo=mapSubNetNodeInfo + slf.localSubNetMapNode=localSubNetMapNode + slf.localSubNetMapService = localSubNetMapService + slf.localNodeMapService = localNodeMapService + slf.localsubnet = subnet + slf.localNodeInfo =localNodeInfo + + //读取服务 + + return err +} + + +func (slf *Cluster) IsConfigService(servicename string) bool { + _,ok := slf.localNodeMapService[servicename] + return ok +} + +func (slf *Cluster) GetNodeIdByService(servicename string) []int{ + var nodelist []int + nodeInfoList,ok := slf.localSubNetMapService[servicename] + if ok == true { + for _,node := range nodeInfoList { + nodelist = append(nodelist,node.NodeId) + } + } + + return nodelist +} + +func (slf *Cluster) GetServiceCfg(servicename string) interface{}{ + v,ok := slf.localNodeServiceCfg[servicename] + if ok == false{ + return nil + } + + return v +} diff --git a/doc/origin分布式框架.pptx b/doc/origin分布式框架.pptx deleted file mode 100644 index 5d7f754..0000000 Binary files a/doc/origin分布式框架.pptx and /dev/null differ diff --git a/event/event.go b/event/event.go new file mode 100644 index 0000000..2f3a109 --- /dev/null +++ b/event/event.go @@ -0,0 +1,80 @@ +package event + +import ( + "github.com/duanhf2012/originnet/log" + "sync" +) + +const Default_EventChannelLen = 10000 + +//事件接受器 +type EventReciver func(event *Event) error + +type Event struct { + Type EventType + Data interface{} +} + +type IEventProcessor interface { + NotifyEvent(*Event) + OnEventHandler(event *Event) error + SetEventReciver(eventProcessor IEventProcessor) + GetEventReciver() IEventProcessor + SetEventChanNum(num int32) bool +} + +type EventProcessor struct { + //事件管道 + EventChan chan *Event + eventReciver IEventProcessor + + eventChanNumLocker sync.RWMutex + eventChanNum int32 +} + +func (slf *EventProcessor) NotifyEvent(pEvent *Event) { + if len(slf.EventChan) >= int(slf.eventChanNum) { + log.Error("event queue is full!") + } + slf.EventChan <-pEvent +} + +func (slf *EventProcessor) OnEventHandler(event *Event) error{ + return nil +} + +func (slf *EventProcessor) GetEventChan() chan *Event{ + slf.eventChanNumLocker.Lock() + defer slf.eventChanNumLocker.Unlock() + + if slf.eventChanNum == 0 { + slf.eventChanNum = Default_EventChannelLen + } + + if slf.EventChan == nil { + slf.EventChan = make(chan *Event,slf.eventChanNum) + } + + return slf.EventChan +} + +//不允许重复设置 +func (slf *EventProcessor) SetEventChanNum(num int32) bool { + slf.eventChanNumLocker.Lock() + defer slf.eventChanNumLocker.Unlock() + if slf.eventChanNum>0 { + return false + } + + slf.eventChanNum = num + return true +} + +func (slf *EventProcessor) SetEventReciver(eventProcessor IEventProcessor){ + slf.eventReciver = eventProcessor +} + + +func (slf *EventProcessor) GetEventReciver() IEventProcessor{ + return slf.eventReciver +} diff --git a/event/eventtype.go b/event/eventtype.go new file mode 100644 index 0000000..89ee333 --- /dev/null +++ b/event/eventtype.go @@ -0,0 +1,14 @@ +package event + +type EventType int + +//大于Sys_Event_User_Define给用户定义 +const ( + Sys_Event_Tcp_Connected EventType= 1 + Sys_Event_Tcp_DisConnected EventType= 2 + Sys_Event_Tcp_RecvPack EventType = 3 + + + Sys_Event_User_Define EventType = 1000 +) + diff --git a/example/GateService/GateService.go b/example/GateService/GateService.go new file mode 100644 index 0000000..079e1c9 --- /dev/null +++ b/example/GateService/GateService.go @@ -0,0 +1,43 @@ +package GateService + +import ( + "github.com/duanhf2012/originnet/event" + "github.com/duanhf2012/originnet/node" + "github.com/duanhf2012/originnet/service" + "github.com/duanhf2012/originnet/sysservice" +) + +type GateService struct { + processor *PBProcessor + service.Service +} + +func (slf *GateService) OnInit() error{ + tcpervice := node.GetService("TcpService").(*sysservice.TcpService) + tcpervice.SetProcessor(&PBProcessor{}) + return nil +} + + +func (slf *GateService) OnEventHandler(ev *event.Event) error{ + if ev.Type == event.Sys_Event_Tcp_RecvPack { + pPack := ev.Data.(*sysservice.TcpPack) + slf.processor.Route(pPack.Data,pPack.ClientId) + }else if ev.Type == event.Sys_Event_Tcp_Connected { + pPack := ev.Data.(*sysservice.TcpPack) + slf.OnConnected(pPack.ClientId) + }else if ev.Type == event.Sys_Event_Tcp_DisConnected { + pPack := ev.Data.(*sysservice.TcpPack) + slf.OnDisconnected(pPack.ClientId) + } + return nil +} + +func (slf *GateService) OnConnected(clientid uint64){ + +} + + +func (slf *GateService) OnDisconnected(clientid uint64){ + +} diff --git a/example/GateService/pbprocessor.go b/example/GateService/pbprocessor.go new file mode 100644 index 0000000..7396680 --- /dev/null +++ b/example/GateService/pbprocessor.go @@ -0,0 +1,79 @@ +package GateService + +import ( + "encoding/binary" + "fmt" + "github.com/golang/protobuf/proto" + "reflect" +) + +type MessageInfo struct { + msgType reflect.Type + msgHandler MessageHandler +} + + +type PBProcessor struct { + mapMsg map[uint16]MessageInfo + LittleEndian bool +} + +func (slf *PBProcessor) SetLittleEndian(littleEndian bool){ + slf.LittleEndian = littleEndian +} + +type PackInfo struct { + typ uint16 + msg proto.Message +} + +// must goroutine safe +func (slf *PBProcessor ) Route(msg interface{},userdata interface{}) error{ + pPackInfo := msg.(*PackInfo) + v,ok := slf.mapMsg[pPackInfo.typ] + if ok == false { + return fmt.Errorf("cannot find msgtype %d is register!",pPackInfo.typ) + } + + + v.msgHandler(userdata.(uint64),pPackInfo.msg) + return nil +} + +// must goroutine safe +func (slf *PBProcessor ) Unmarshal(data []byte) (interface{}, error) { + var msgType uint16 + if slf.LittleEndian == true { + msgType = binary.LittleEndian.Uint16(data[:2]) + }else{ + msgType = binary.BigEndian.Uint16(data[:2]) + } + + info,ok := slf.mapMsg[msgType] + if ok == false { + return nil,fmt.Errorf("cannot find register %d msgtype!",msgType) + } + msg := reflect.New(info.msgType.Elem()).Interface() + protoMsg := msg.(proto.Message) + err := proto.Unmarshal(data[2:], protoMsg) + if err != nil { + return nil,err + } + + return &PackInfo{typ:msgType,msg:protoMsg},nil +} + +// must goroutine safe +func (slf *PBProcessor ) Marshal(msg interface{}) ([]byte, error){ + return proto.Marshal(msg.(proto.Message)) +} + +type MessageHandler func(clientid uint64,msg proto.Message) + +func (slf *PBProcessor) Register(msgtype uint16,msg proto.Message,handle MessageHandler) { + var info MessageInfo + + info.msgType = reflect.TypeOf(msg.(proto.Message)) + info.msgHandler = handle + slf.mapMsg[msgtype] = info +} diff --git a/example/config/cluster/subnet/cluster.json b/example/config/cluster/subnet/cluster.json new file mode 100644 index 0000000..a97970f --- /dev/null +++ b/example/config/cluster/subnet/cluster.json @@ -0,0 +1,23 @@ +{ + "NodeList":[ + { + "NodeId": 1, + "ListenAddr":"127.0.0.1:8001", + "NodeName": "Node_Test1", + "remark":"//以_打头的,表示只在本机进程,不对整个子网开发", + "ServiceList": ["TestService1","TestService2","TestServiceCall"] + }, + { + "NodeId": 2, + "ListenAddr":"127.0.0.1:8002", + "NodeName": "Node_Gate2", + "ServiceList": ["SubNet1_Service"] + }, + { + "NodeId": 3, + "ListenAddr":"127.0.0.1:8003", + "NodeName": "Node_Room", + "ServiceList": ["SubNet1_Service"] + } + ] +} \ No newline at end of file diff --git a/example/config/cluster/subnet/service.json b/example/config/cluster/subnet/service.json new file mode 100644 index 0000000..1a7666a --- /dev/null +++ b/example/config/cluster/subnet/service.json @@ -0,0 +1,13 @@ +{ + "HttpService":{ + "Port":10001 + }, + "TcpService":{ + "ListenAddr":"0.0.0.0:9030", + "MaxConnNum":3000, + "PendingWriteNum":10000, + "LittleEndian":false, + "MinMsgLen":4, + "MaxMsgLen":65535 + } +} \ No newline at end of file diff --git a/example/main.exe.pid b/example/main.exe.pid new file mode 100644 index 0000000..9057483 --- /dev/null +++ b/example/main.exe.pid @@ -0,0 +1 @@ +49288 \ No newline at end of file diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..7e699be --- /dev/null +++ b/example/main.go @@ -0,0 +1,202 @@ +package main + +import ( + "fmt" + "github.com/duanhf2012/originnet/example/GateService" + "github.com/duanhf2012/originnet/node" + "github.com/duanhf2012/originnet/service" + "github.com/duanhf2012/originnet/sysmodule" + "github.com/duanhf2012/originnet/sysservice" + "time" +) + +type TestService1 struct { + service.Service +} + +type TestService2 struct { + service.Service +} + +type TestServiceCall struct { + service.Service + dbModule sysmodule.DBModule +} + +func init(){ + node.Setup(&TestService1{},&TestService2{},&TestServiceCall{}) +} + +type Module1 struct{ + service.Module +} + +type Module2 struct{ + service.Module +} + +type Module3 struct{ + service.Module +} + +type Module4 struct{ + service.Module +} +var moduleid1 int64 +var moduleid2 int64 +var moduleid3 int64 +var moduleid4 int64 + +func (slf *Module1) OnInit() error { + fmt.Printf("I'm Module1:%d\n",slf.GetModuleId()) + return nil +} + +func (slf *Module2) OnInit() error { + fmt.Printf("I'm Module2:%d\n",slf.GetModuleId()) + moduleid3,_ = slf.AddModule(&Module3{}) + return nil +} +func (slf *Module3) OnInit() error { + fmt.Printf("I'm Module3:%d\n",slf.GetModuleId()) + moduleid4,_ = slf.AddModule(&Module4{}) + + return nil +} + +func (slf *Module4) OnInit() error { + fmt.Printf("I'm Module4:%d\n",slf.GetModuleId()) + //pService := slf.GetService().(*TestServiceCall) + //pService.RPC_Test(nil,nil) + slf.AfterFunc(time.Second*10,slf.TimerTest) + return nil +} + +func (slf *Module4) TimerTest(){ + fmt.Printf("Module4 tigger timer\n") +} + +func (slf *Module1) OnRelease() { + fmt.Printf("Release Module1:%d\n",slf.GetModuleId()) +} +func (slf *Module2) OnRelease() { + fmt.Printf("Release Module2:%d\n",slf.GetModuleId()) +} +func (slf *Module3) OnRelease() { + fmt.Printf("Release Module3:%d\n",slf.GetModuleId()) +} +func (slf *Module4) OnRelease() { + fmt.Printf("Release Module4:%d\n",slf.GetModuleId()) +} + +func (slf *TestServiceCall) OnInit() error { + slf.AfterFunc(time.Second*1,slf.Run) + moduleid1,_ = slf.AddModule(&Module1{}) + moduleid2,_ = slf.AddModule(&Module2{}) + fmt.Print(moduleid1,moduleid2) + + slf.dbModule = sysmodule.DBModule{} + slf.dbModule.Init(10,3, "192.168.0.5:3306", "root", "Root!!2018", "Matrix") + slf.dbModule.SetQuerySlowTime(time.Second * 3) + slf.AddModule(&slf.dbModule) + + slf.AfterFunc(time.Second*5,slf.Release) + slf.AfterFunc(time.Second, slf.TestDB) + return nil +} + +func (slf *TestServiceCall) Release(){ + slf.ReleaseModule(moduleid1) + slf.ReleaseModule(moduleid2) +} + + +type Param struct { + Index int + A int + B string + Pa []string +} + + +func (slf *TestServiceCall) Run(){ + //var ret int + var input int = 10000 + bT := time.Now() // 开始时间 + + //err := slf.Call("TestServiceCall.RPC_Test",&ret,&input) + var param Param + param.A = 2342342341 + param.B = "xxxxxxxxxxxxxxxxxxxxxxx" + param.Pa = []string{"ccccc","asfsdfsdaf","bbadfsdf","ewrwefasdf","safsadfka;fksd"} + + for i:=input;i>=0;i--{ + param.Index = i + slf.AsyncCall("TestService1.RPC_Test",¶m, func(reply *Param, err error) { + if reply.Index == 0 || err != nil{ + eT := time.Since(bT) // 从开始到当前所消耗的时间 + fmt.Print(err,eT.Milliseconds()) + fmt.Print("..................",eT,"\n") + } + //fmt.Print(*reply,"\n",err) + }) + + } + + fmt.Print("finsh....") + + +} + +func (slf *TestService1) RPC_Test(a *Param,b *Param) error { + *a = *b + return nil +} + +func (slf *TestService1) OnInit() error { + return nil +} + +func (slf *TestServiceCall) RPC_Test(a *int,b *int) error { + fmt.Printf("TestService2\n") + *a = *b + return nil +} + +func (slf *TestServiceCall) TestDB() { + assetsInfo := &struct { + Cash int64 `json:"cash"` //美金余额 100 + Gold int64 `json:"gold"` //金币余额 + Heart int64 `json:"heart"` //心数 + }{} + sql := `call sp_select_userAssets(?)` + userID := 100000802 + err := slf.dbModule.AsyncQuery(func(dataList *sysmodule.DataSetList, err error) { + if err != nil { + return + } + err = dataList.UnMarshal(assetsInfo) + if err != nil { + return + } + },-1, sql, &userID) + + fmt.Println(err) +} + +func (slf *TestService2) OnInit() error { + return nil +} + +func main(){ + node.Init() + tcpService := &sysservice.TcpService{} + gateService := &GateService.GateService{} + + tcpService.SetEventReciver(gateService) + node.Setup(tcpService,gateService) + + node.Start() +} + + diff --git a/example/serviceTest/OriginServeOne.go b/example/serviceTest/OriginServeOne.go new file mode 100644 index 0000000..36385e7 --- /dev/null +++ b/example/serviceTest/OriginServeOne.go @@ -0,0 +1,64 @@ +package serviceTest + +import ( + "fmt" + "github.com/duanhf2012/originnet/service" + "time" +) + +type TestAsyn struct { + a int + b string +} + +type OriginServerOne struct { + service.Service +} + +func (slf *OriginServerOne) OnInit() error { + //slf.AfterFunc(time.Second,slf.testCall) + //slf.AfterFunc(time.Second*5,slf.testCall) + //slf.AfterFunc(time.Second*10, slf.testGRCall) + //slf.AfterFunc(time.Second*15, slf.testGRCall) + //slf.AfterFunc(time.Second, slf.testAsyncCall) + slf.AfterFunc(time.Second, slf.testAsyncGRCall) + return nil +} + +func (slf *OriginServerOne) testCall() { + a := 1 + b := 10 + slf.Call("OriginServerTwo.RPC_TestCall", &a, &b) + fmt.Println(b) +} + +func (slf *OriginServerOne) testGRCall() { + a := 1 + b := 10 + slf.GRCall("OriginServerTwo.RPC_TestCall", &a, &b) + fmt.Println(b) +} + +func (slf *OriginServerOne) testAsyncCall() { + for i := 0; i < 100; i++ { + in := i + bT := time.Now() + slf.AsyncCall("OriginServerTwo.RPC_TestAsyncCall", &in, func(reply *TestAsyn, err error) { + eT := time.Since(bT) // 从开始到当前所消耗的时间 + fmt.Println(reply, eT) + }) + fmt.Println(in) + } +} + +func (slf *OriginServerOne) testAsyncGRCall() { + for i := 0; i < 100; i++ { + in := i + bT := time.Now() + slf.GRAsyncCall("OriginServerTwo.RPC_TestAsyncCall", &in, func(reply *TestAsyn, err error) { + eT := time.Since(bT) + fmt.Println(reply, eT) + }) + fmt.Println(in) + } +} \ No newline at end of file diff --git a/example/serviceTest/OriginServerTwo.go b/example/serviceTest/OriginServerTwo.go new file mode 100644 index 0000000..caf32ad --- /dev/null +++ b/example/serviceTest/OriginServerTwo.go @@ -0,0 +1,27 @@ +package serviceTest + +import ( + "fmt" + "github.com/duanhf2012/originnet/service" + "time" +) + +type OriginServerTwo struct { + service.Service +} + +func (slf *OriginServerTwo) RPC_TestCall(a *int,b *int) error { + fmt.Printf("OriginServerTwo\n") + *a = *b*2 + //slf.AfterFunc(time.Second,slf.Test) + return nil +} + +func (slf *OriginServerTwo) RPC_TestAsyncCall(a *int, reply *TestAsyn) error { + fmt.Printf("OriginServerTwo async start sleep %d\n", *a) + time.Sleep(time.Second) + + reply.a = *a + reply.b = "fuck!" + return nil +} diff --git a/log/example_test.go b/log/example_test.go new file mode 100644 index 0000000..55f5c35 --- /dev/null +++ b/log/example_test.go @@ -0,0 +1,29 @@ +package log_test + +import ( + "github.com/name5566/leaf/log" + l "log" +) + +func Example() { + name := "Leaf" + + log.Debug("My name is %v", name) + log.Release("My name is %v", name) + log.Error("My name is %v", name) + // log.Fatal("My name is %v", name) + + logger, err := log.New("release", "", l.LstdFlags) + if err != nil { + return + } + defer logger.Close() + + logger.Debug("will not print") + logger.Release("My name is %v", name) + + log.Export(logger) + + log.Debug("will not print") + log.Release("My name is %v", name) +} diff --git a/log/log.go b/log/log.go new file mode 100644 index 0000000..1c7cab9 --- /dev/null +++ b/log/log.go @@ -0,0 +1,153 @@ +package log + +import ( + "errors" + "fmt" + "log" + "os" + "path" + "strings" + "time" +) + +// levels +const ( + debugLevel = 0 + releaseLevel = 1 + errorLevel = 2 + fatalLevel = 3 +) + +const ( + printDebugLevel = "[debug ] " + printReleaseLevel = "[release] " + printErrorLevel = "[error ] " + printFatalLevel = "[fatal ] " +) + +type Logger struct { + level int + baseLogger *log.Logger + baseFile *os.File +} + +func New(strLevel string, pathname string, flag int) (*Logger, error) { + // level + var level int + switch strings.ToLower(strLevel) { + case "debug": + level = debugLevel + case "release": + level = releaseLevel + case "error": + level = errorLevel + case "fatal": + level = fatalLevel + default: + return nil, errors.New("unknown level: " + strLevel) + } + + // logger + var baseLogger *log.Logger + var baseFile *os.File + if pathname != "" { + now := time.Now() + + filename := fmt.Sprintf("%d%02d%02d_%02d_%02d_%02d.log", + now.Year(), + now.Month(), + now.Day(), + now.Hour(), + now.Minute(), + now.Second()) + + file, err := os.Create(path.Join(pathname, filename)) + if err != nil { + return nil, err + } + + baseLogger = log.New(file, "", flag) + baseFile = file + } else { + baseLogger = log.New(os.Stdout, "", flag) + } + + // new + logger := new(Logger) + logger.level = level + logger.baseLogger = baseLogger + logger.baseFile = baseFile + + return logger, nil +} + +// It's dangerous to call the method on logging +func (logger *Logger) Close() { + if logger.baseFile != nil { + logger.baseFile.Close() + } + + logger.baseLogger = nil + logger.baseFile = nil +} + +func (logger *Logger) doPrintf(level int, printLevel string, format string, a ...interface{}) { + if level < logger.level { + return + } + if logger.baseLogger == nil { + panic("logger closed") + } + + format = printLevel + format + logger.baseLogger.Output(3, fmt.Sprintf(format, a...)) + + if level == fatalLevel { + os.Exit(1) + } +} + +func (logger *Logger) Debug(format string, a ...interface{}) { + logger.doPrintf(debugLevel, printDebugLevel, format, a...) +} + +func (logger *Logger) Release(format string, a ...interface{}) { + logger.doPrintf(releaseLevel, printReleaseLevel, format, a...) +} + +func (logger *Logger) Error(format string, a ...interface{}) { + logger.doPrintf(errorLevel, printErrorLevel, format, a...) +} + +func (logger *Logger) Fatal(format string, a ...interface{}) { + logger.doPrintf(fatalLevel, printFatalLevel, format, a...) +} + +var gLogger, _ = New("debug", "", log.LstdFlags) + +// It's dangerous to call the method on logging +func Export(logger *Logger) { + if logger != nil { + gLogger = logger + } +} + +func Debug(format string, a ...interface{}) { + gLogger.doPrintf(debugLevel, printDebugLevel, format, a...) +} + +func Release(format string, a ...interface{}) { + gLogger.doPrintf(releaseLevel, printReleaseLevel, format, a...) +} + +func Error(format string, a ...interface{}) { + gLogger.doPrintf(errorLevel, printErrorLevel, format, a...) +} + +func Fatal(format string, a ...interface{}) { + gLogger.doPrintf(fatalLevel, printFatalLevel, format, a...) +} + +func Close() { + gLogger.Close() +} diff --git a/network/agent.go b/network/agent.go new file mode 100644 index 0000000..7f174b6 --- /dev/null +++ b/network/agent.go @@ -0,0 +1,6 @@ +package network + +type Agent interface { + Run() + OnClose() +} diff --git a/network/conn.go b/network/conn.go new file mode 100644 index 0000000..9f7a2c5 --- /dev/null +++ b/network/conn.go @@ -0,0 +1,14 @@ +package network + +import ( + "net" +) + +type Conn interface { + ReadMsg() ([]byte, error) + WriteMsg(args ...[]byte) error + LocalAddr() net.Addr + RemoteAddr() net.Addr + Close() + Destroy() +} diff --git a/network/httpserver.go b/network/httpserver.go deleted file mode 100644 index 24831ab..0000000 --- a/network/httpserver.go +++ /dev/null @@ -1,98 +0,0 @@ -package network - -import ( - "crypto/tls" - "fmt" - "net/http" - "os" - "time" - - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysmodule" -) - -type CA struct { - certfile string - keyfile string -} - -type HttpServer struct { - port uint16 - - handler http.Handler - readtimeout time.Duration - writetimeout time.Duration - - httpserver *http.Server - caList []CA - - ishttps bool -} - -func (slf *HttpServer) Init(port uint16, handler http.Handler, readtimeout time.Duration, writetimeout time.Duration) { - slf.port = port - slf.handler = handler - slf.readtimeout = readtimeout - slf.writetimeout = writetimeout -} - -func (slf *HttpServer) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) { - http.HandleFunc(pattern, handler) -} - -func (slf *HttpServer) Start() { - go slf.startListen() -} - -func (slf *HttpServer) startListen() error { - listenPort := fmt.Sprintf(":%d", slf.port) - - var tlscatList []tls.Certificate - var tlsConfig *tls.Config - for _, cadata := range slf.caList { - cer, err := tls.LoadX509KeyPair(cadata.certfile, cadata.keyfile) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "load CA [%s]-[%s] file is error :%s", cadata.certfile, cadata.keyfile, err.Error()) - os.Exit(1) - return nil - } - tlscatList = append(tlscatList, cer) - } - - if len(tlscatList) > 0 { - tlsConfig = &tls.Config{Certificates: tlscatList} - } - - slf.httpserver = &http.Server{ - Addr: listenPort, - Handler: slf.handler, - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - TLSConfig: tlsConfig, - } - - var err error - if slf.ishttps == true { - err = slf.httpserver.ListenAndServeTLS("", "") - } else { - err = slf.httpserver.ListenAndServe() - } - - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "http.ListenAndServe(%d, nil) error:%v\n", listenPort, err) - fmt.Printf("http.ListenAndServe(%d, %v) error\n", slf.port, err) - os.Exit(1) - } - - return nil -} - -func (slf *HttpServer) SetHttps(certfile string, keyfile string) bool { - if certfile == "" || keyfile == "" { - return false - } - slf.caList = append(slf.caList, CA{certfile, keyfile}) - slf.ishttps = true - return true -} diff --git a/network/netserver.go b/network/netserver.go new file mode 100644 index 0000000..2ce8a2b --- /dev/null +++ b/network/netserver.go @@ -0,0 +1,7 @@ +package network + +type inetserver interface { + +} + + diff --git a/network/processor.go b/network/processor.go new file mode 100644 index 0000000..7739434 --- /dev/null +++ b/network/processor.go @@ -0,0 +1,10 @@ +package network + +type Processor interface { + // must goroutine safe + Route(msg interface{}, userData interface{}) error + // must goroutine safe + Unmarshal(data []byte) (interface{}, error) + // must goroutine safe + Marshal(msg interface{}) ([]byte, error) +} diff --git a/network/processor/gobprocessor.go b/network/processor/gobprocessor.go new file mode 100644 index 0000000..95af6c9 --- /dev/null +++ b/network/processor/gobprocessor.go @@ -0,0 +1 @@ +package processor diff --git a/network/processor/jsonprocessor.go b/network/processor/jsonprocessor.go new file mode 100644 index 0000000..106b9cb --- /dev/null +++ b/network/processor/jsonprocessor.go @@ -0,0 +1,17 @@ +package processor + +type JsonProcessor struct { + //SetByteOrder(littleEndian bool) + //SetMsgLen(lenMsgLen int, minMsgLen uint32, maxMsgLen uint32) + + +} + +func (slf *JsonProcessor) Unmarshal(data []byte) (interface{}, error) { + return nil,nil +} + + +func (slf *JsonProcessor) Marshal(msg interface{}) ([][]byte, error) { + return nil,nil +} \ No newline at end of file diff --git a/network/processor/msgpackprocessor.go b/network/processor/msgpackprocessor.go new file mode 100644 index 0000000..95af6c9 --- /dev/null +++ b/network/processor/msgpackprocessor.go @@ -0,0 +1 @@ +package processor diff --git a/network/processor/processor.go b/network/processor/processor.go new file mode 100644 index 0000000..e98d88c --- /dev/null +++ b/network/processor/processor.go @@ -0,0 +1,11 @@ +package processor + +type IProcessor interface { + //SetByteOrder(littleEndian bool) + //SetMsgLen(lenMsgLen int, minMsgLen uint32, maxMsgLen uint32) + + Unmarshal(data []byte) (interface{}, error) + // must goroutine safe + Marshal(msg interface{}) ([][]byte, error) +} + diff --git a/network/processor/protobufprocessor.go b/network/processor/protobufprocessor.go new file mode 100644 index 0000000..95af6c9 --- /dev/null +++ b/network/processor/protobufprocessor.go @@ -0,0 +1 @@ +package processor diff --git a/network/tcp_client.go b/network/tcp_client.go new file mode 100644 index 0000000..1db8199 --- /dev/null +++ b/network/tcp_client.go @@ -0,0 +1,130 @@ +package network + +import ( + "github.com/duanhf2012/originnet/log" + "net" + "sync" + "time" +) + +type TCPClient struct { + sync.Mutex + Addr string + ConnNum int + ConnectInterval time.Duration + PendingWriteNum int + AutoReconnect bool + NewAgent func(*TCPConn) Agent + conns ConnSet + wg sync.WaitGroup + closeFlag bool + + // msg parser + LenMsgLen int + MinMsgLen uint32 + MaxMsgLen uint32 + LittleEndian bool + msgParser *MsgParser +} + +func (client *TCPClient) Start() { + client.init() + + for i := 0; i < client.ConnNum; i++ { + client.wg.Add(1) + go client.connect() + } +} + +func (client *TCPClient) init() { + client.Lock() + defer client.Unlock() + + if client.ConnNum <= 0 { + client.ConnNum = 1 + log.Release("invalid ConnNum, reset to %v", client.ConnNum) + } + if client.ConnectInterval <= 0 { + client.ConnectInterval = 3 * time.Second + log.Release("invalid ConnectInterval, reset to %v", client.ConnectInterval) + } + if client.PendingWriteNum <= 0 { + client.PendingWriteNum = 100 + log.Release("invalid PendingWriteNum, reset to %v", client.PendingWriteNum) + } + if client.NewAgent == nil { + log.Fatal("NewAgent must not be nil") + } + if client.conns != nil { + log.Fatal("client is running") + } + + client.conns = make(ConnSet) + client.closeFlag = false + + // msg parser + msgParser := NewMsgParser() + msgParser.SetMsgLen(client.LenMsgLen, client.MinMsgLen, client.MaxMsgLen) + msgParser.SetByteOrder(client.LittleEndian) + client.msgParser = msgParser +} + +func (client *TCPClient) dial() net.Conn { + for { + conn, err := net.Dial("tcp", client.Addr) + if err == nil || client.closeFlag { + return conn + } + + log.Release("connect to %v error: %v", client.Addr, err) + time.Sleep(client.ConnectInterval) + continue + } +} + +func (client *TCPClient) connect() { + defer client.wg.Done() + +reconnect: + conn := client.dial() + if conn == nil { + return + } + + client.Lock() + if client.closeFlag { + client.Unlock() + conn.Close() + return + } + client.conns[conn] = struct{}{} + client.Unlock() + + tcpConn := newTCPConn(conn, client.PendingWriteNum, client.msgParser) + agent := client.NewAgent(tcpConn) + agent.Run() + + // cleanup + tcpConn.Close() + client.Lock() + delete(client.conns, conn) + client.Unlock() + agent.OnClose() + + if client.AutoReconnect { + time.Sleep(client.ConnectInterval) + goto reconnect + } +} + +func (client *TCPClient) Close() { + client.Lock() + client.closeFlag = true + for conn := range client.conns { + conn.Close() + } + client.conns = nil + client.Unlock() + + client.wg.Wait() +} diff --git a/network/tcp_conn.go b/network/tcp_conn.go new file mode 100644 index 0000000..489be77 --- /dev/null +++ b/network/tcp_conn.go @@ -0,0 +1,113 @@ +package network + +import ( + "github.com/duanhf2012/originnet/log" + "net" + "sync" +) + +type ConnSet map[net.Conn]struct{} + +type TCPConn struct { + sync.Mutex + conn net.Conn + writeChan chan []byte + closeFlag bool + msgParser *MsgParser +} + +func newTCPConn(conn net.Conn, pendingWriteNum int, msgParser *MsgParser) *TCPConn { + tcpConn := new(TCPConn) + tcpConn.conn = conn + tcpConn.writeChan = make(chan []byte, pendingWriteNum) + tcpConn.msgParser = msgParser + + go func() { + for b := range tcpConn.writeChan { + if b == nil { + break + } + + _, err := conn.Write(b) + if err != nil { + break + } + } + + conn.Close() + tcpConn.Lock() + tcpConn.closeFlag = true + tcpConn.Unlock() + }() + + return tcpConn +} + +func (tcpConn *TCPConn) doDestroy() { + tcpConn.conn.(*net.TCPConn).SetLinger(0) + tcpConn.conn.Close() + + if !tcpConn.closeFlag { + close(tcpConn.writeChan) + tcpConn.closeFlag = true + } +} + +func (tcpConn *TCPConn) Destroy() { + tcpConn.Lock() + defer tcpConn.Unlock() + + tcpConn.doDestroy() +} + +func (tcpConn *TCPConn) Close() { + tcpConn.Lock() + defer tcpConn.Unlock() + if tcpConn.closeFlag { + return + } + + tcpConn.doWrite(nil) + tcpConn.closeFlag = true +} + +func (tcpConn *TCPConn) doWrite(b []byte) { + if len(tcpConn.writeChan) == cap(tcpConn.writeChan) { + log.Debug("close conn: channel full") + tcpConn.doDestroy() + return + } + + tcpConn.writeChan <- b +} + +// b must not be modified by the others goroutines +func (tcpConn *TCPConn) Write(b []byte) { + tcpConn.Lock() + defer tcpConn.Unlock() + if tcpConn.closeFlag || b == nil { + return + } + + tcpConn.doWrite(b) +} + +func (tcpConn *TCPConn) Read(b []byte) (int, error) { + return tcpConn.conn.Read(b) +} + +func (tcpConn *TCPConn) LocalAddr() net.Addr { + return tcpConn.conn.LocalAddr() +} + +func (tcpConn *TCPConn) RemoteAddr() net.Addr { + return tcpConn.conn.RemoteAddr() +} + +func (tcpConn *TCPConn) ReadMsg() ([]byte, error) { + return tcpConn.msgParser.Read(tcpConn) +} + +func (tcpConn *TCPConn) WriteMsg(args ...[]byte) error { + return tcpConn.msgParser.Write(tcpConn, args...) +} diff --git a/network/tcp_msg.go b/network/tcp_msg.go new file mode 100644 index 0000000..6b309c4 --- /dev/null +++ b/network/tcp_msg.go @@ -0,0 +1,154 @@ +package network + +import ( + "encoding/binary" + "errors" + "io" + "math" +) + +// -------------- +// | len | data | +// -------------- +type MsgParser struct { + lenMsgLen int + minMsgLen uint32 + maxMsgLen uint32 + littleEndian bool +} + +func NewMsgParser() *MsgParser { + p := new(MsgParser) + p.lenMsgLen = 2 + p.minMsgLen = 1 + p.maxMsgLen = 4096 + p.littleEndian = false + + return p +} + +// It's dangerous to call the method on reading or writing +func (p *MsgParser) SetMsgLen(lenMsgLen int, minMsgLen uint32, maxMsgLen uint32) { + if lenMsgLen == 1 || lenMsgLen == 2 || lenMsgLen == 4 { + p.lenMsgLen = lenMsgLen + } + if minMsgLen != 0 { + p.minMsgLen = minMsgLen + } + if maxMsgLen != 0 { + p.maxMsgLen = maxMsgLen + } + + var max uint32 + switch p.lenMsgLen { + case 1: + max = math.MaxUint8 + case 2: + max = math.MaxUint16 + case 4: + max = math.MaxUint32 + } + if p.minMsgLen > max { + p.minMsgLen = max + } + if p.maxMsgLen > max { + p.maxMsgLen = max + } +} + +// It's dangerous to call the method on reading or writing +func (p *MsgParser) SetByteOrder(littleEndian bool) { + p.littleEndian = littleEndian +} + +// goroutine safe +func (p *MsgParser) Read(conn *TCPConn) ([]byte, error) { + var b [4]byte + bufMsgLen := b[:p.lenMsgLen] + + // read len + if _, err := io.ReadFull(conn, bufMsgLen); err != nil { + return nil, err + } + + // parse len + var msgLen uint32 + switch p.lenMsgLen { + case 1: + msgLen = uint32(bufMsgLen[0]) + case 2: + if p.littleEndian { + msgLen = uint32(binary.LittleEndian.Uint16(bufMsgLen)) + } else { + msgLen = uint32(binary.BigEndian.Uint16(bufMsgLen)) + } + case 4: + if p.littleEndian { + msgLen = binary.LittleEndian.Uint32(bufMsgLen) + } else { + msgLen = binary.BigEndian.Uint32(bufMsgLen) + } + } + + // check len + if msgLen > p.maxMsgLen { + return nil, errors.New("message too long") + } else if msgLen < p.minMsgLen { + return nil, errors.New("message too short") + } + + // data + msgData := make([]byte, msgLen) + if _, err := io.ReadFull(conn, msgData); err != nil { + return nil, err + } + + return msgData, nil +} + +// goroutine safe +func (p *MsgParser) Write(conn *TCPConn, args ...[]byte) error { + // get len + var msgLen uint32 + for i := 0; i < len(args); i++ { + msgLen += uint32(len(args[i])) + } + + // check len + if msgLen > p.maxMsgLen { + return errors.New("message too long") + } else if msgLen < p.minMsgLen { + return errors.New("message too short") + } + + msg := make([]byte, uint32(p.lenMsgLen)+msgLen) + + // write len + switch p.lenMsgLen { + case 1: + msg[0] = byte(msgLen) + case 2: + if p.littleEndian { + binary.LittleEndian.PutUint16(msg, uint16(msgLen)) + } else { + binary.BigEndian.PutUint16(msg, uint16(msgLen)) + } + case 4: + if p.littleEndian { + binary.LittleEndian.PutUint32(msg, msgLen) + } else { + binary.BigEndian.PutUint32(msg, msgLen) + } + } + + // write data + l := p.lenMsgLen + for i := 0; i < len(args); i++ { + copy(msg[l:], args[i]) + l += len(args[i]) + } + + conn.Write(msg) + + return nil +} diff --git a/network/tcp_server.go b/network/tcp_server.go new file mode 100644 index 0000000..385fb6f --- /dev/null +++ b/network/tcp_server.go @@ -0,0 +1,127 @@ +package network + +import ( + "github.com/duanhf2012/originnet/log" + "net" + "sync" + "time" +) + +type TCPServer struct { + Addr string + MaxConnNum int + PendingWriteNum int + NewAgent func(*TCPConn) Agent + ln net.Listener + conns ConnSet + mutexConns sync.Mutex + wgLn sync.WaitGroup + wgConns sync.WaitGroup + + // msg parser + LenMsgLen int + MinMsgLen uint32 + MaxMsgLen uint32 + LittleEndian bool + msgParser *MsgParser +} + +func (server *TCPServer) Start() { + server.init() + go server.run() +} + +func (server *TCPServer) init() { + ln, err := net.Listen("tcp", server.Addr) + if err != nil { + log.Fatal("%v", err) + } + + if server.MaxConnNum <= 0 { + server.MaxConnNum = 100 + log.Release("invalid MaxConnNum, reset to %v", server.MaxConnNum) + } + if server.PendingWriteNum <= 0 { + server.PendingWriteNum = 100 + log.Release("invalid PendingWriteNum, reset to %v", server.PendingWriteNum) + } + if server.NewAgent == nil { + log.Fatal("NewAgent must not be nil") + } + + server.ln = ln + server.conns = make(ConnSet) + + // msg parser + msgParser := NewMsgParser() + msgParser.SetMsgLen(server.LenMsgLen, server.MinMsgLen, server.MaxMsgLen) + msgParser.SetByteOrder(server.LittleEndian) + server.msgParser = msgParser +} + +func (server *TCPServer) run() { + server.wgLn.Add(1) + defer server.wgLn.Done() + + var tempDelay time.Duration + for { + conn, err := server.ln.Accept() + if err != nil { + if ne, ok := err.(net.Error); ok && ne.Temporary() { + if tempDelay == 0 { + tempDelay = 5 * time.Millisecond + } else { + tempDelay *= 2 + } + if max := 1 * time.Second; tempDelay > max { + tempDelay = max + } + log.Release("accept error: %v; retrying in %v", err, tempDelay) + time.Sleep(tempDelay) + continue + } + return + } + tempDelay = 0 + + server.mutexConns.Lock() + if len(server.conns) >= server.MaxConnNum { + server.mutexConns.Unlock() + conn.Close() + log.Debug("too many connections") + continue + } + server.conns[conn] = struct{}{} + server.mutexConns.Unlock() + + server.wgConns.Add(1) + + tcpConn := newTCPConn(conn, server.PendingWriteNum, server.msgParser) + agent := server.NewAgent(tcpConn) + go func() { + agent.Run() + + // cleanup + tcpConn.Close() + server.mutexConns.Lock() + delete(server.conns, conn) + server.mutexConns.Unlock() + agent.OnClose() + + server.wgConns.Done() + }() + } +} + +func (server *TCPServer) Close() { + server.ln.Close() + server.wgLn.Wait() + + server.mutexConns.Lock() + for conn := range server.conns { + conn.Close() + } + server.conns = nil + server.mutexConns.Unlock() + server.wgConns.Wait() +} diff --git a/network/tcpsocketclient.go b/network/tcpsocketclient.go deleted file mode 100644 index 3985755..0000000 --- a/network/tcpsocketclient.go +++ /dev/null @@ -1,48 +0,0 @@ -package network - -import ( - "fmt" - "github.com/golang/protobuf/proto" - "net" -) - -type TcpSocketClient struct { - conn net.Conn - addr string -} - -func (slf *TcpSocketClient) Connect(addr string) error{ - tcpAddr,terr := net.ResolveTCPAddr("tcp",addr) - if terr != nil { - return terr - } - - conn,err := net.DialTCP("tcp",nil,tcpAddr) - if err!=nil { - fmt.Println("Client connect error ! " + err.Error()) - return err - } - slf.conn = conn - slf.addr = addr - - // - return nil -} - -func (slf *TcpSocketClient) SendMsg(packtype uint16,message proto.Message) error{ - if slf.conn == nil { - return fmt.Errorf("cannt connect %s",slf.addr) - } - - var msg MsgBasePack - data,err := proto.Marshal(message) - if err != nil { - return err - } - - msg.Make(packtype,data) - - slf.conn.Write(msg.Bytes()) - - return nil -} diff --git a/network/tcpsocketserver.go b/network/tcpsocketserver.go deleted file mode 100644 index 9c34c73..0000000 --- a/network/tcpsocketserver.go +++ /dev/null @@ -1,331 +0,0 @@ -package network - -import ( - "bufio" - "encoding/binary" - "fmt" - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/util" - "github.com/golang/protobuf/proto" - "io" - "net" - "unsafe" - - "os" - "time" -) - -type ITcpSocketServerReciver interface { - OnConnected(pClient *SClient) - OnDisconnect(pClient *SClient) - OnRecvMsg(pClient *SClient, pPack *MsgBasePack) -} - - -type SClient struct { - id uint64 - conn net.Conn - - recvPack *util.SyncQueue - sendPack *util.SyncQueue - tcpserver *TcpSocketServer - remoteip string - starttime int64 - bClose bool -} - -type TcpSocketServer struct { - listenAddr string //ip:port - mapClient util.Map - - MaxRecvPackSize uint16 - MaxSendPackSize uint16 - iReciver ITcpSocketServerReciver - nodelay bool -} - -type MsgBasePack struct { - PackSize uint16 - PackType uint16 - Body []byte - StartTime time.Time -} - - - - - -func (slf *TcpSocketServer) Register(listenAddr string,iReciver ITcpSocketServerReciver){ - slf.listenAddr = listenAddr - slf.iReciver = iReciver -} - - -func (slf *TcpSocketServer) Start(){ - slf.MaxRecvPackSize = 2048 - slf.MaxSendPackSize = 40960 - - util.Go(slf.listenServer) -} - -func (slf *TcpSocketServer) listenServer(){ - slf.nodelay = true - - listener, err := net.Listen("tcp", slf.listenAddr) - if err != nil { - service.GetLogger().Printf(service.LEVER_FATAL, "TcpSocketServer Listen error %+v",err) - os.Exit(1) - } - - var clientId uint64 - for { - conn, aerr := listener.Accept() - if aerr != nil { - service.GetLogger().Printf(service.LEVER_FATAL, "TcpSocketServer accept error %+v",aerr) - continue - } - - if slf.nodelay { - //conn.(ifaceSetNoDelay) - } - for { - clientId += 1 - if slf.mapClient.Get(clientId)!= nil { - continue - } - - sc :=&SClient{id:clientId,conn:conn,tcpserver:slf,remoteip:conn.RemoteAddr().String(),starttime:time.Now().UnixNano(), - recvPack:util.NewSyncQueue(),sendPack:util.NewSyncQueue()} - - slf.mapClient.Set(clientId,sc) - util.Go(sc.listendata) - //收来自客户端数据 - util.Go(sc.onrecv) - //发送数据队列 - util.Go(sc.onsend) - - break - } - } -} - -func (slf *TcpSocketServer) Close(clientid uint64) error { - pClient := slf.mapClient.Get(clientid) - if pClient == nil { - return fmt.Errorf("clientid %d is not in connect pool.",clientid) - } - - pClient.(*SClient).Close() - return nil -} - -func (slf *TcpSocketServer) SendMsg(clientid uint64,packtype uint16,message proto.Message) error{ - pClient := slf.mapClient.Get(clientid) - if pClient == nil { - return fmt.Errorf("clientid %d is not in connect pool.",clientid) - } - - return pClient.(*SClient).SendMsg(packtype,message) -} - -func (slf *TcpSocketServer) Send(clientid uint64,pack *MsgBasePack) error{ - pClient := slf.mapClient.Get(clientid) - if pClient == nil { - return fmt.Errorf("clientid %d is not in connect pool.",clientid) - } - - return pClient.(*SClient).Send(pack) -} - - -func (slf *SClient) listendata(){ - defer func() { - slf.Close() - slf.tcpserver.mapClient.Del(slf.id) - slf.tcpserver.iReciver.OnDisconnect(slf) - service.GetLogger().Printf(service.LEVER_DEBUG, "clent id %d return listendata...",slf.id) - }() - - slf.tcpserver.iReciver.OnConnected(slf) - //获取一个连接的reader读取流 - reader := bufio.NewReader(slf.conn) - - //临时接受数据的buff - var buff []byte //tmprecvbuf - var tmpbuff []byte - var buffDataSize uint16 - tmpbuff = make([]byte,2048) - - //解析包数据 - var pack MsgBasePack - for { - n,err := reader.Read(tmpbuff) - if err != nil || err == io.EOF { - service.GetLogger().Printf(service.LEVER_INFO, "clent id %d is disconnect %+v",slf.id,err) - return - } - buff = append(buff,tmpbuff[:n]...) - buffDataSize += uint16(n) - if buffDataSize> slf.tcpserver.MaxRecvPackSize { - service.GetLogger().Print(service.LEVER_WARN,"recv client id %d data size %d is over %d",slf.id,buffDataSize,slf.tcpserver.MaxRecvPackSize) - return - } - - fillsize,bfillRet,fillhead := pack.FillData(buff,buffDataSize) - //提交校验头 - if fillhead == true { - if pack.PackSize>slf.tcpserver.MaxRecvPackSize { - service.GetLogger().Printf(service.LEVER_WARN, "VerifyPackType error clent id %d is disconnect %d,%d",slf.id,pack.PackType, pack.PackSize) - return - } - } - if bfillRet == true { - slf.recvPack.Push(pack) - pack = MsgBasePack{} - } - if fillsize>0 { - buff = append(buff[fillsize:]) - buffDataSize -= fillsize - } - } -} - - -func (slf *MsgBasePack) Bytes() []byte{ - var bRet []byte - bRet = make([]byte,4) - binary.BigEndian.PutUint16(bRet,slf.PackSize) - binary.BigEndian.PutUint16(bRet[2:],slf.PackType) - bRet = append(bRet,slf.Body...) - - return bRet -} - -//返回值:填充多少字节,是否完成,是否填充头 -func (slf *MsgBasePack) FillData(bdata []byte,datasize uint16) (uint16,bool,bool) { - var fillsize uint16 - fillhead := false - //解包头 - if slf.PackSize ==0 { - if datasize < 4 { - return 0,false,fillhead - } - - slf.PackSize= binary.BigEndian.Uint16(bdata[:2]) - slf.PackType= binary.BigEndian.Uint16(bdata[2:4]) - fillsize += 4 - fillhead = true - } - - //解包体 - if slf.PackSize>0 && datasize+4>=slf.PackSize { - slf.Body = append(slf.Body, bdata[fillsize:slf.PackSize]...) - fillsize += (slf.PackSize - fillsize) - return fillsize,true,fillhead - } - - return fillsize,false,fillhead -} - - -func (slf *MsgBasePack) Clear() { -} - -func (slf *MsgBasePack) Make(packtype uint16,data []byte) { - slf.PackType = packtype - slf.Body = data - slf.PackSize = uint16(unsafe.Sizeof(slf.PackType)*2)+uint16(len(data)) -} - -func (slf *SClient) Send(pack *MsgBasePack) error { - if slf.bClose == true { - return fmt.Errorf("client id %d is close!",slf.id) - } - - slf.sendPack.Push(pack) - - return nil -} - - -func (slf *SClient) SendMsg(packtype uint16,message proto.Message) error{ - if slf.bClose == true { - return fmt.Errorf("client id %d is close!",slf.id) - } - - var msg MsgBasePack - data,err := proto.Marshal(message) - if err != nil { - return err - } - - msg.Make(packtype,data) - slf.sendPack.Push(&msg) - - return nil -} - - - -func (slf *SClient) onsend(){ - defer func() { - slf.Close() - service.GetLogger().Printf(service.LEVER_DEBUG, "clent id %d return onsend...",slf.id) - }() - - for { - pack,ok := slf.sendPack.TryPop() - if slf.bClose == true { - break - } - if ok == false || pack == nil { - time.Sleep(time.Millisecond*1) - continue - } - - pPackData := pack.(*MsgBasePack) - _,e := slf.conn.Write(pPackData.Bytes()) - if e!=nil { - service.GetLogger().Printf(service.LEVER_DEBUG, "clent id %d write error...",slf.id) - return - } - //fmt.Print("xxxxxxxxxxxxxxx:",n,e) - } -} - -func (slf *SClient) onrecv(){ - defer func() { - slf.Close() - service.GetLogger().Printf(service.LEVER_DEBUG, "clent id %d return onrecv...",slf.id) - }() - - for { - pack,ok := slf.recvPack.TryPop() - if slf.bClose == true { - break - } - if ok == false || pack == nil { - time.Sleep(time.Millisecond*1) - continue - } - - pMsg := pack.(MsgBasePack) - slf.tcpserver.iReciver.OnRecvMsg(slf,&pMsg) - } -} - - -func (slf *SClient) Close(){ - if slf.bClose == false { - slf.conn.Close() - slf.bClose = true - - slf.recvPack.Close() - slf.sendPack.Close() - } -} - - -func (slf *SClient) GetId() uint64{ - return slf.id -} diff --git a/network/websocketclient.go b/network/websocketclient.go deleted file mode 100644 index 6d82eb9..0000000 --- a/network/websocketclient.go +++ /dev/null @@ -1,259 +0,0 @@ -package network - -import ( - "errors" - "fmt" - "net/http" - "net/url" - "runtime/debug" - - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysmodule" - - "github.com/gorilla/websocket" - - "time" -) - -//IWebsocketClient ... -type IWebsocketClient interface { - Init(slf IWebsocketClient, strurl, strProxyPath string, timeoutsec time.Duration) error - Start() error - WriteMessage(msg []byte) error - OnDisconnect() error - OnConnected() error - OnReadMessage(msg []byte) error - ReConnect() -} - -//WebsocketClient ... -type WebsocketClient struct { - WsDailer *websocket.Dialer - conn *websocket.Conn - url string - state int //0未连接状态 1正在重连 2连接状态 - bwritemsg chan []byte - closer chan bool - slf IWebsocketClient - timeoutsec time.Duration - - bRun bool - ping []byte -} - -const ( - MAX_WRITE_MSG = 10240 -) - -//Init ... -func (ws *WebsocketClient) Init(slf IWebsocketClient, strurl, strProxyPath string, timeoutsec time.Duration) error { - - ws.timeoutsec = timeoutsec - ws.slf = slf - if strProxyPath != "" { - proxy := func(_ *http.Request) (*url.URL, error) { - return url.Parse(strProxyPath) - } - - if timeoutsec > 0 { - tosec := timeoutsec * time.Second - ws.WsDailer = &websocket.Dialer{Proxy: proxy, HandshakeTimeout: tosec} - } else { - ws.WsDailer = &websocket.Dialer{Proxy: proxy} - } - } else { - if timeoutsec > 0 { - tosec := timeoutsec * time.Second - ws.WsDailer = &websocket.Dialer{HandshakeTimeout: tosec} - } else { - ws.WsDailer = &websocket.Dialer{} - } - } - - ws.url = strurl - ws.ping = []byte(`ping`) - return nil -} - -func (ws *WebsocketClient) SetPing(ping string) { - ws.ping = []byte(ping) -} - -//OnRun ... -func (ws *WebsocketClient) OnRun() error { - defer func() { - if r := recover(); r != nil { - coreInfo := string(debug.Stack()) - coreInfo += "\n" + fmt.Sprintf("Core WebsocketClient url is %s. Core information is %v\n", ws.url, r) - service.GetLogger().Printf(service.LEVER_FATAL, coreInfo) - go ws.OnRun() - } - }() - - for { - if ws.bRun == false { - break - } - - if ws.state == 0 { - time.Sleep(2 * time.Second) - ws.StartConnect() - } else if ws.state == 1 { - ws.state = 0 - close(ws.closer) - ws.conn.Close() - ws.slf.OnDisconnect() - } else if ws.state == 2 { - ws.conn.SetReadDeadline(time.Now().Add(ws.timeoutsec * time.Second)) - _, message, err := ws.conn.ReadMessage() - - if err != nil { - service.GetLogger().Printf(service.LEVER_WARN, "websocket client is disconnect [%s],information is %v", ws.url, err) - ws.conn.Close() - ws.state = 0 - close(ws.closer) - ws.slf.OnDisconnect() - continue - } - - ws.slf.OnReadMessage(message) - } - } - - return nil -} - -//StartConnect ... -func (ws *WebsocketClient) StartConnect() error { - - var err error - ws.conn, _, err = ws.WsDailer.Dial(ws.url, nil) - service.GetLogger().Printf(sysmodule.LEVER_INFO, "connecting %s, %+v\n", ws.url, err) - if err != nil { - return err - } - ws.closer = make(chan bool) - ws.bwritemsg = make(chan []byte, MAX_WRITE_MSG) - ws.state = 2 - ws.slf.OnConnected() - - return nil -} - -//Start ... -func (ws *WebsocketClient) Start() error { - - if ws.bRun == false { - ws.bRun = true - ws.state = 0 - go ws.OnRun() - go ws.writeMsg() - } - return nil -} - -//触发 -func (ws *WebsocketClient) writeMsg() error { - //dump处理 - defer func() { - if r := recover(); r != nil { - coreInfo := string(debug.Stack()) - coreInfo += "\n" + fmt.Sprintf("Core WebsocketClient url is %s. Core information is %v\n", ws.url, r) - service.GetLogger().Printf(service.LEVER_FATAL, coreInfo) - go ws.writeMsg() - } - }() - - timerC := time.NewTicker(time.Second * 5).C - for { - if ws.bRun == false { - break - } - - if ws.state == 0 { - time.Sleep(1 * time.Second) - continue - } - select { - case _, ok := <-ws.closer: - if ok == false { - break - } - - case <-timerC: - if ws.state == 2 { - err := ws.WriteMessage(ws.ping) - if err != nil { - service.GetLogger().Printf(service.LEVER_WARN, "websocket client is disconnect [%s],information is %v", ws.url, err) - ws.state = 0 - ws.conn.Close() - ws.slf.OnDisconnect() - } - } - case msg, ok := <-ws.bwritemsg: - if ok == true && ws.state == 2 { - ws.conn.SetWriteDeadline(time.Now().Add(ws.timeoutsec * time.Second)) - err := ws.conn.WriteMessage(websocket.TextMessage, msg) - if err != nil { - service.GetLogger().Printf(service.LEVER_WARN, "websocket client is disconnect [%s],information is %v", ws.url, err) - ws.state = 0 - ws.conn.Close() - ws.slf.OnDisconnect() - } - } - } - } - - return nil -} - -//ReConnect ... -func (ws *WebsocketClient) ReConnect() { - ws.state = 1 -} - -//WriteMessage ... -func (ws *WebsocketClient) WriteMessage(msg []byte) error { - if ws.closer == nil || ws.bwritemsg == nil { - service.GetLogger().Printf(service.LEVER_WARN, "WriteMessage data fail,websocket client is disconnect.") - return errors.New("riteMessage data fail,websocket client is disconnect.") - } - select { - case <-ws.closer: - service.GetLogger().Printf(service.LEVER_WARN, "WriteMessage data fail,websocket client is disconnect.") - return errors.New("riteMessage data fail,websocket client is disconnect.") - default: - if len(ws.bwritemsg) < MAX_WRITE_MSG { - ws.bwritemsg <- msg - } else { - service.GetLogger().Printf(service.LEVER_ERROR, "WriteMessage data fail,bwriteMsg is overload.") - return errors.New("WriteMessage data fail,bwriteMsg is overload.") - } - - } - - return nil -} - -//OnDisconnect ... -func (ws *WebsocketClient) OnDisconnect() error { - - return nil -} - -//OnConnected ... -func (ws *WebsocketClient) OnConnected() error { - - return nil -} - -//OnReadMessage 触发 -func (ws *WebsocketClient) OnReadMessage(msg []byte) error { - - return nil -} - -//Stop ... -func (ws *WebsocketClient) Stop() { - ws.bRun = false -} diff --git a/network/websocketserver.go b/network/websocketserver.go deleted file mode 100644 index f42f952..0000000 --- a/network/websocketserver.go +++ /dev/null @@ -1,328 +0,0 @@ -package network - -import ( - "crypto/tls" - "errors" - "fmt" - "github.com/duanhf2012/origin/util" - "net/http" - "os" - "runtime/debug" - "sync" - "time" - - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysmodule" - - "github.com/gorilla/mux" - "github.com/gorilla/websocket" - "github.com/gotoxu/cors" -) - -type IWebsocketServer interface { - SendMsg(clientid uint64, messageType int, msg []byte) bool - CreateClient(conn *websocket.Conn) *WSClient - Disconnect(clientid uint64) - ReleaseClient(pclient *WSClient) - Clients() []uint64 - BroadcastMsg(messageType int, msg []byte) int -} - -type IMessageReceiver interface { - initReciver(messageReciver IMessageReceiver, websocketServer IWebsocketServer) - - OnConnected(clientid uint64) - OnDisconnect(clientid uint64, err error) - OnRecvMsg(clientid uint64, msgtype int, data []byte) - OnHandleHttp(w http.ResponseWriter, r *http.Request) - IsInit() bool -} - -type Reciver struct { - messageReciver IMessageReceiver - bEnableCompression bool -} - -type BaseMessageReciver struct { - messageReciver IMessageReceiver - WsServer IWebsocketServer -} - -type WSClient struct { - clientid uint64 - conn *websocket.Conn - bwritemsg chan WSMessage -} - -type WSMessage struct { - msgtype int - bwritemsg []byte -} - -type WebsocketServer struct { - wsUri string - maxClientid uint64 //记录当前最新clientid - mapClient map[uint64]*WSClient - locker sync.RWMutex - - port uint16 - - httpserver *http.Server - reciver map[string]Reciver - - caList []CA - - iswss bool -} - -const ( - MAX_MSG_COUNT = 20480 -) - -func (slf *WebsocketServer) Init(port uint16) { - slf.port = port - slf.mapClient = make(map[uint64]*WSClient) -} - -func (slf *WebsocketServer) CreateClient(conn *websocket.Conn) *WSClient { - slf.locker.Lock() - slf.maxClientid++ - clientid := slf.maxClientid - pclient := &WSClient{clientid, conn, make(chan WSMessage, MAX_MSG_COUNT+1)} - slf.mapClient[pclient.clientid] = pclient - slf.locker.Unlock() - - service.GetLogger().Printf(sysmodule.LEVER_INFO, "Client id %d is connected.", clientid) - return pclient -} - -func (slf *WebsocketServer) ReleaseClient(pclient *WSClient) { - pclient.conn.Close() - slf.locker.Lock() - delete(slf.mapClient, pclient.clientid) - slf.locker.Unlock() - //关闭写管道 - close(pclient.bwritemsg) - service.GetLogger().Printf(sysmodule.LEVER_INFO, "Client id %d is disconnected.", pclient.clientid) -} - -func (slf *WebsocketServer) SetupReciver(pattern string, messageReciver IMessageReceiver, bEnableCompression bool) { - messageReciver.initReciver(messageReciver, slf) - - if slf.reciver == nil { - slf.reciver = make(map[string]Reciver) - } - slf.reciver[pattern] = Reciver{messageReciver, bEnableCompression} -} - -func (slf *WebsocketServer) startListen() { - listenPort := fmt.Sprintf(":%d", slf.port) - - var tlscatList []tls.Certificate - var tlsConfig *tls.Config - for _, cadata := range slf.caList { - cer, err := tls.LoadX509KeyPair(cadata.certfile, cadata.keyfile) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "load CA %s-%s file is error :%s", cadata.certfile, cadata.keyfile, err.Error()) - os.Exit(1) - return - } - tlscatList = append(tlscatList, cer) - } - - if len(tlscatList) > 0 { - tlsConfig = &tls.Config{Certificates: tlscatList} - } - - slf.httpserver = &http.Server{ - Addr: listenPort, - Handler: slf.initRouterHandler(), - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - TLSConfig: tlsConfig, - } - - var err error - if slf.iswss == true { - err = slf.httpserver.ListenAndServeTLS("", "") - } else { - err = slf.httpserver.ListenAndServe() - } - - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "http.ListenAndServe(%d, nil) error:%v\n", slf.port, err) - os.Exit(1) - } -} - -func (slf *WSClient) startSendMsg() { - for { - msgbuf, ok := <-slf.bwritemsg - if ok == false { - break - } - slf.conn.SetWriteDeadline(time.Now().Add(15 * time.Second)) - err := slf.conn.WriteMessage(msgbuf.msgtype, msgbuf.bwritemsg) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_INFO, "write client id %d is error :%v\n", slf.clientid, err) - break - } - } -} - -func (slf *WebsocketServer) Start() { - - go slf.startListen() -} - -func (slf *WebsocketServer) Clients() []uint64 { - slf.locker.RLock() - defer slf.locker.RUnlock() - r := make([]uint64, 0, len(slf.mapClient)) - for i, _ := range slf.mapClient { - r = append(r, i) - } - return r -} - -func (slf *WebsocketServer) BroadcastMsg(messageType int, msg []byte) int { - slf.locker.RLock() - defer slf.locker.RUnlock() - err := 0 - wsMsg := WSMessage{messageType, msg} - for _, value := range slf.mapClient { - if len(value.bwritemsg) >= MAX_MSG_COUNT { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "message chan is full :%d\n", len(value.bwritemsg)) - err++ - } - value.bwritemsg <- wsMsg - } - return err -} - -func (slf *WebsocketServer) SendMsg(clientid uint64, messageType int, msg []byte) bool { - slf.locker.RLock() - defer slf.locker.RUnlock() - value, ok := slf.mapClient[clientid] - if ok == false { - return false - } - - if len(value.bwritemsg) >= MAX_MSG_COUNT { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "message chan is full :%d\n", len(value.bwritemsg)) - return false - } - - value.bwritemsg <- WSMessage{messageType, msg} - - return true -} - -func (slf *WebsocketServer) Disconnect(clientid uint64) { - slf.locker.Lock() - defer slf.locker.Unlock() - value, ok := slf.mapClient[clientid] - if ok == false { - return - } - - value.conn.Close() -} - -func (slf *WebsocketServer) Stop() { -} - -func (slf *BaseMessageReciver) startReadMsg(pclient *WSClient) { - defer func() { - if r := recover(); r != nil { - var coreInfo string - coreInfo = string(debug.Stack()) - coreInfo += "\n" + fmt.Sprintf("Core information is %v\n", r) - service.GetLogger().Printf(service.LEVER_FATAL, coreInfo) - slf.messageReciver.OnDisconnect(pclient.clientid, errors.New("Core dump")) - slf.WsServer.ReleaseClient(pclient) - } - }() - - var maxTimeStamp int64 - var maxMsgType int - logMinMsgTime :=time.Millisecond*300 - - statisticsIntervalTm := util.Timer{} - statisticsIntervalTm.SetupTimer(1000 * 15)//15秒间隔 - for { - pclient.conn.SetReadDeadline(time.Now().Add(15 * time.Second)) - msgtype, message, err := pclient.conn.ReadMessage() - if err != nil { - slf.messageReciver.OnDisconnect(pclient.clientid, err) - slf.WsServer.ReleaseClient(pclient) - - return - } - - if statisticsIntervalTm.CheckTimeOut() { - service.GetLogger().Printf(service.LEVER_INFO, "MaxMsgtype:%d,diff:%d",maxMsgType,maxTimeStamp) - } - //记录处理时间 - startRecvTm := time.Now().UnixNano() - slf.messageReciver.OnRecvMsg(pclient.clientid, msgtype, message) - diff := time.Now().UnixNano() - startRecvTm - if diff> maxTimeStamp{ - maxTimeStamp = diff - maxMsgType = msgtype - } - if diff >= int64(logMinMsgTime) { - service.GetLogger().Printf(service.LEVER_WARN, "Process slowly MaxMsgtype:%d,diff:%d",maxMsgType,maxTimeStamp) - } - } -} - -func (slf *BaseMessageReciver) initReciver(messageReciver IMessageReceiver, websocketServer IWebsocketServer) { - slf.messageReciver = messageReciver - slf.WsServer = websocketServer -} - -func (slf *BaseMessageReciver) OnConnected(clientid uint64) { -} - -func (slf *BaseMessageReciver) OnDisconnect(clientid uint64, err error) { -} - -func (slf *BaseMessageReciver) OnRecvMsg(clientid uint64, msgtype int, data []byte) { -} - -func (slf *BaseMessageReciver) OnHandleHttp(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024) - if err != nil { - http.Error(w, "Could not open websocket connection", http.StatusBadRequest) - return - } - - pclient := slf.WsServer.CreateClient(conn) - slf.messageReciver.OnConnected(pclient.clientid) - go pclient.startSendMsg() - go slf.startReadMsg(pclient) -} - -func (slf *WebsocketServer) initRouterHandler() http.Handler { - r := mux.NewRouter() - - for pattern, reciver := range slf.reciver { - if reciver.messageReciver.IsInit() == true { - r.HandleFunc(pattern, reciver.messageReciver.OnHandleHttp) - } - } - - cors := cors.AllowAll() - return cors.Handler(r) -} - -func (slf *WebsocketServer) SetWSS(certfile string, keyfile string) bool { - if certfile == "" || keyfile == "" { - return false - } - slf.caList = append(slf.caList, CA{certfile, keyfile}) - slf.iswss = true - return true -} diff --git a/network/wsagentserver.go b/network/wsagentserver.go deleted file mode 100644 index 6734878..0000000 --- a/network/wsagentserver.go +++ /dev/null @@ -1,323 +0,0 @@ -package network - -import ( - "crypto/tls" - "errors" - "fmt" - "net/http" - "os" - "reflect" - "runtime/debug" - "sync" - "time" - - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysmodule" - "github.com/gotoxu/cors" - - "github.com/gorilla/mux" - "github.com/gorilla/websocket" -) - -type IWSAgentServer interface { - SendMsg(agentid uint32, messageType int, msg []byte) bool - CreateAgent(urlPattern string, conn *websocket.Conn) IAgent - Disconnect(agentid uint32) - ReleaseAgent(iagent IAgent) -} - -type IAgent interface { - initAgent(conn *websocket.Conn, agentid uint32, iagent IAgent, WSAgentServer IWSAgentServer) - startReadMsg() - startSendMsg() - OnConnected() - OnDisconnect(err error) - OnRecvMsg(msgtype int, data []byte) - //OnHandleHttp(w http.ResponseWriter, r *http.Request) - GetAgentId() uint32 - getConn() *websocket.Conn - getWriteMsgChan() chan WSAgentMessage -} - -type BaseAgent struct { - service.BaseModule - WsServer IWSAgentServer - agent IAgent - agentid uint32 - conn *websocket.Conn - bwritemsg chan WSAgentMessage - iagent IAgent -} - -type WSAgentMessage struct { - msgtype int - bwritemsg []byte -} - -type WSAgentServer struct { - service.BaseModule - wsUri string - maxAgentid uint32 //记录当前最新agentid - //mapAgent map[uint32]IAgent - locker sync.Mutex - - port uint16 - - httpserver *http.Server - regAgent map[string]reflect.Type - - caList []CA - iswss bool -} - -const ( - MAX_AGENT_MSG_COUNT = 20480 -) - -func (slf *WSAgentServer) Init(port uint16) { - slf.port = port -} - -func (slf *WSAgentServer) CreateAgent(urlPattern string, conn *websocket.Conn) IAgent { - slf.locker.Lock() - iAgent, ok := slf.regAgent[urlPattern] - if ok == false { - slf.locker.Unlock() - service.GetLogger().Printf(sysmodule.LEVER_WARN, "Cannot find %s pattern!", urlPattern) - return nil - } - - v := reflect.New(iAgent).Elem().Addr().Interface() - if v == nil { - slf.locker.Unlock() - service.GetLogger().Printf(sysmodule.LEVER_WARN, "new %s pattern agent type is error!", urlPattern) - return nil - } - - pModule := v.(service.IModule) - iagent := v.(IAgent) - slf.maxAgentid++ - agentid := slf.maxAgentid - iagent.initAgent(conn, agentid, iagent, slf) - slf.AddModule(pModule) - - slf.locker.Unlock() - - service.GetLogger().Printf(sysmodule.LEVER_INFO, "Agent id %d is connected.", iagent.GetAgentId()) - return iagent -} - -func (slf *WSAgentServer) ReleaseAgent(iagent IAgent) { - iagent.getConn().Close() - slf.locker.Lock() - slf.ReleaseModule(iagent.GetAgentId()) - //delete(slf.mapAgent, iagent.GetAgentId()) - slf.locker.Unlock() - //关闭写管道 - close(iagent.getWriteMsgChan()) - service.GetLogger().Printf(sysmodule.LEVER_INFO, "Agent id %d is disconnected.", iagent.GetAgentId()) -} - -func (slf *WSAgentServer) SetupAgent(pattern string, agent IAgent, bEnableCompression bool) { - if slf.regAgent == nil { - slf.regAgent = make(map[string]reflect.Type) - } - - slf.regAgent[pattern] = reflect.TypeOf(agent).Elem() //reflect.TypeOf(agent).Elem() -} - -func (slf *WSAgentServer) startListen() { - listenPort := fmt.Sprintf(":%d", slf.port) - - var tlscatList []tls.Certificate - var tlsConfig *tls.Config - for _, cadata := range slf.caList { - cer, err := tls.LoadX509KeyPair(cadata.certfile, cadata.keyfile) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "load CA %s-%s file is error :%s", cadata.certfile, cadata.keyfile, err.Error()) - os.Exit(1) - return - } - tlscatList = append(tlscatList, cer) - } - - if len(tlscatList) > 0 { - tlsConfig = &tls.Config{Certificates: tlscatList} - } - - slf.httpserver = &http.Server{ - Addr: listenPort, - Handler: slf.initRouterHandler(), - ReadTimeout: 10 * time.Second, - WriteTimeout: 10 * time.Second, - MaxHeaderBytes: 1 << 20, - TLSConfig: tlsConfig, - } - - var err error - if slf.iswss == true { - err = slf.httpserver.ListenAndServeTLS("", "") - } else { - err = slf.httpserver.ListenAndServe() - } - - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_FATAL, "http.ListenAndServe(%d, nil) error:%v\n", slf.port, err) - os.Exit(1) - } -} - -func (slf *BaseAgent) startSendMsg() { - for { - msgbuf, ok := <-slf.bwritemsg - if ok == false { - break - } - slf.conn.SetWriteDeadline(time.Now().Add(15 * time.Second)) - err := slf.conn.WriteMessage(msgbuf.msgtype, msgbuf.bwritemsg) - if err != nil { - service.GetLogger().Printf(sysmodule.LEVER_INFO, "write agent id %d is error :%v\n", slf.GetAgentId(), err) - break - } - } -} - -func (slf *WSAgentServer) Start() { - go slf.startListen() -} - -func (slf *WSAgentServer) GetAgentById(agentid uint32) IAgent { - pModule := slf.GetModuleById(agentid) - if pModule == nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "GetAgentById :%d is fail.\n", agentid) - return nil - } - - return pModule.(IAgent) -} - -func (slf *WSAgentServer) SendMsg(agentid uint32, messageType int, msg []byte) bool { - slf.locker.Lock() - defer slf.locker.Unlock() - - iagent := slf.GetAgentById(agentid) - if iagent == nil { - return false - } - - if len(iagent.getWriteMsgChan()) >= MAX_AGENT_MSG_COUNT { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "message chan is full :%d\n", len(iagent.getWriteMsgChan())) - return false - } - - iagent.getWriteMsgChan() <- WSAgentMessage{messageType, msg} - - return true -} - -func (slf *WSAgentServer) Disconnect(agentid uint32) { - slf.locker.Lock() - defer slf.locker.Unlock() - iagent := slf.GetAgentById(agentid) - if iagent == nil { - return - } - - iagent.getConn().Close() -} - -func (slf *WSAgentServer) Stop() { -} - -func (slf *BaseAgent) startReadMsg() { - defer func() { - if r := recover(); r != nil { - var coreInfo string - coreInfo = string(debug.Stack()) - coreInfo += "\n" + fmt.Sprintf("Core information is %v\n", r) - service.GetLogger().Printf(service.LEVER_FATAL, coreInfo) - slf.agent.OnDisconnect(errors.New("Core dump")) - slf.WsServer.ReleaseAgent(slf.agent) - } - }() - - slf.agent.OnConnected() - for { - slf.conn.SetReadDeadline(time.Now().Add(15 * time.Second)) - msgtype, message, err := slf.conn.ReadMessage() - if err != nil { - slf.agent.OnDisconnect(err) - slf.WsServer.ReleaseAgent(slf.agent) - return - } - - slf.agent.OnRecvMsg(msgtype, message) - } -} - -func (slf *WSAgentServer) initRouterHandler() http.Handler { - r := mux.NewRouter() - - for pattern, _ := range slf.regAgent { - r.HandleFunc(pattern, slf.OnHandleHttp) - } - - cors := cors.AllowAll() - return cors.Handler(r) -} - -func (slf *WSAgentServer) SetWSS(certfile string, keyfile string) bool { - if certfile == "" || keyfile == "" { - return false - } - slf.caList = append(slf.caList, CA{certfile, keyfile}) - slf.iswss = true - return true -} - -func (slf *BaseAgent) GetAgentId() uint32 { - return slf.agentid -} - -func (slf *BaseAgent) initAgent(conn *websocket.Conn, agentid uint32, iagent IAgent, WSAgentServer IWSAgentServer) { - slf.agent = iagent - slf.WsServer = WSAgentServer - slf.bwritemsg = make(chan WSAgentMessage, MAX_AGENT_MSG_COUNT) - slf.agentid = agentid - slf.conn = conn -} - -func (slf *BaseAgent) OnConnected() { -} - -func (slf *BaseAgent) OnDisconnect(err error) { -} - -func (slf *BaseAgent) OnRecvMsg(msgtype int, data []byte) { -} - -func (slf *BaseAgent) getConn() *websocket.Conn { - return slf.conn -} - -func (slf *BaseAgent) getWriteMsgChan() chan WSAgentMessage { - return slf.bwritemsg -} - -func (slf *BaseAgent) SendMsg(agentid uint32, messageType int, msg []byte) bool { - return slf.WsServer.SendMsg(agentid, messageType, msg) -} - -func (slf *WSAgentServer) OnHandleHttp(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024) - if err != nil { - http.Error(w, "Could not open websocket connection!", http.StatusBadRequest) - return - } - - agent := slf.CreateAgent(r.URL.Path, conn) - fmt.Print(agent.GetAgentId()) - slf.AddModule(agent.(service.IModule)) - go agent.startSendMsg() - go agent.startReadMsg() -} diff --git a/node/node.go b/node/node.go new file mode 100644 index 0000000..7fb8517 --- /dev/null +++ b/node/node.go @@ -0,0 +1,115 @@ +package node + +import ( + "fmt" + "github.com/duanhf2012/originnet/service" + "github.com/duanhf2012/originnet/cluster" + "io/ioutil" + "os" + "os/signal" + "strconv" + "syscall" + "time" +) + +var closeSig chan bool +var sigs chan os.Signal + +var preSetupService []service.IService //预安装 + +func init() { + closeSig = make(chan bool,1) + sigs = make(chan os.Signal, 3) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM,syscall.Signal(10)) +} + + +func getRunProcessPid() (int,error) { + f, err := os.OpenFile(os.Args[0]+".pid", os.O_RDONLY, 0600) + defer f.Close() + if err!= nil { + return 0,err + } + + pidbyte,errs := ioutil.ReadAll(f) + if errs!=nil { + return 0,errs + } + + return strconv.Atoi(string(pidbyte)) +} + +func writeProcessPid() { + //pid + f, err := os.OpenFile(os.Args[0]+".pid", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0600) + defer f.Close() + if err != nil { + fmt.Println(err.Error()) + os.Exit(-1) + } else { + _,err=f.Write([]byte(fmt.Sprintf("%d",os.Getpid()))) + if err != nil { + fmt.Println(err.Error()) + os.Exit(-1) + } + } +} + +func GetNodeId() int { + return 1 +} + +func Init(){ + //1.初始化集群 + err := cluster.GetCluster().Init(GetNodeId()) + if err != nil { + panic(err) + } + + //2.service模块初始化 + service.Init(closeSig) + + //3.初始化预安装的服务 + for _,s := range preSetupService { + pServiceCfg := cluster.GetCluster().GetServiceCfg(s.GetName()) + s.Init(s,cluster.GetRpcClient,cluster.GetRpcServer,pServiceCfg) + //是否配置的service + if cluster.GetCluster().IsConfigService(s.GetName()) == false { + continue + } + service.Setup(s) + } +} + +func Start() { + cluster.GetCluster().Start() + service.Start() + writeProcessPid() + for { + select { + case <-sigs: + fmt.Printf("Recv stop sig") + break + default: + time.Sleep(time.Second) + } + } + + close(closeSig) + service.WaitStop() +} + + +func Setup(s ...service.IService) { + for _,sv := range s { + preSetupService = append(preSetupService,sv) + } +} + +func GetService(servicename string) service.IService { + return service.GetService(servicename) +} + +func SetConfigDir(configdir string){ + cluster.SetConfigDir(configdir) +} \ No newline at end of file diff --git a/originnode/node.go b/originnode/node.go deleted file mode 100644 index b4133f4..0000000 --- a/originnode/node.go +++ /dev/null @@ -1,175 +0,0 @@ -package originnode - -import ( - "fmt" - "log" - "strconv" - "strings" - "time" - - "github.com/duanhf2012/origin/util" - - "net/http" - _ "net/http/pprof" - "os" - "os/signal" - "sync" - "syscall" - - "github.com/duanhf2012/origin/cluster" - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysmodule" - "github.com/duanhf2012/origin/sysservice" -) - -type CExitCtl struct { - exitChan chan bool - waitGroup *sync.WaitGroup -} - -type COriginNode struct { - CExitCtl - serviceManager service.IServiceManager - sigs chan os.Signal - debugListenAddress string -} - -var initservicelist []service.IService - -func InitService(iservice service.IService) { - initservicelist = append(initservicelist, iservice) -} - -func (s *COriginNode) Init() { - - s.SetupService(initservicelist...) - - //初始化全局模块 - logger := service.InstanceServiceMgr().FindService("syslog").(service.ILogger) - ret := service.InstanceServiceMgr().Init(logger, s.exitChan, s.waitGroup) - if ret == false { - os.Exit(-1) - } - - util.Log = logger.Printf - s.sigs = make(chan os.Signal, 1) - signal.Notify(s.sigs, syscall.SIGINT, syscall.SIGTERM) -} - -// OpenDebugCheck ("localhost:6060")...http://localhost:6060/ -func (s *COriginNode) OpenDebugCheck(listenAddress string) { - s.debugListenAddress = listenAddress -} - -func (s *COriginNode) SetupService(services ...service.IService) { - ppService := &sysservice.PProfService{} - services = append(services, ppService) - cluster.InstanceClusterMgr().AddLocalService(ppService) - for i := 0; i < len(services); i++ { - services[i].Init(services[i]) - - if cluster.InstanceClusterMgr().HasLocalService(services[i].GetServiceName()) == true { - service.InstanceServiceMgr().Setup(services[i]) - } - } -} - -func (s *COriginNode) Start() { - if s.debugListenAddress != "" { - go func() { - log.Println(http.ListenAndServe(s.debugListenAddress, nil)) - }() - } - - //开始运行集群 - cluster.InstanceClusterMgr().Start() - - //开启所有服务 - service.InstanceServiceMgr().Start() - - //监听退出信号 - select { - case <-s.sigs: - service.GetLogger().Printf(sysmodule.LEVER_WARN, "Recv stop sig") - fmt.Printf("Recv stop sig") - } - - //停止运行程序 - s.Stop() - service.GetLogger().Printf(sysmodule.LEVER_INFO, "Node stop run...") -} - -func (s *COriginNode) Stop() { - close(s.exitChan) - s.waitGroup.Wait() -} - -func GetCmdParamNodeId() int { - if len(os.Args) < 2 { - return 0 - //return fmt.Errorf("Param error not find NodeId=number") - } - - parts := strings.Split(os.Args[1], "=") - if len(parts) < 2 { - return 0 - //return fmt.Errorf("Param error not find NodeId=number") - } - - if parts[0] != "NodeId" { - return 0 - //return fmt.Errorf("Param error not find NodeId=number") - } - - //读取配置 - currentNodeid, err := strconv.Atoi(parts[1]) - if err != nil { - return 0 - } - - return currentNodeid -} - -func NewOriginNode() *COriginNode { - CurrentNodeId := GetCmdParamNodeId() - if CurrentNodeId == 0 { - fmt.Print("Param error not find NodeId=number") - os.Exit(-1) - } - - //创建模块 - node := new(COriginNode) - node.exitChan = make(chan bool) - node.waitGroup = &sync.WaitGroup{} - - //安装系统服务 - syslogservice := &sysservice.LogService{} - syslogservice.InitLog("syslog", fmt.Sprintf("syslog_%d", CurrentNodeId), sysmodule.LEVER_DEBUG) - service.InstanceServiceMgr().Setup(syslogservice) - - //初始化集群对象 - err := cluster.InstanceClusterMgr().Init(CurrentNodeId) - if err != nil { - fmt.Print(err) - os.Exit(-1) - return nil - } - - return node -} - -func (s *COriginNode) GetSysLog() *sysservice.LogService { - logService := service.InstanceServiceMgr().FindService("syslog") - if logService == nil { - fmt.Printf("Cannot find syslog service!") - os.Exit(-1) - return nil - } - - return logService.(*sysservice.LogService) -} - -func (s *COriginNode) EnableMonitorModule(checkInterval time.Duration){ - service.EnableDeadForMonitor(checkInterval) -} - diff --git a/rpc/client.go b/rpc/client.go index 4cef3e0..ffa5ddf 100644 --- a/rpc/client.go +++ b/rpc/client.go @@ -1,360 +1,208 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - package rpc import ( - "bufio" - "encoding/gob" - "errors" "fmt" - "io" - "log" - "net" - "net/http" + "github.com/duanhf2012/originnet/log" + "github.com/duanhf2012/originnet/network" + "math" + "reflect" + "strings" "sync" "time" ) -// ServerError represents an error that has been returned from -// the remote side of the RPC connection. -type ServerError string - -func (e ServerError) Error() string { - return string(e) -} - -var ErrShutdown = errors.New("connection is shut down") - -// Call represents an active RPC. -type Call struct { - ServiceMethod string // The name of the service and method to call. - Args interface{} // The argument to the function (*struct). - Reply interface{} // The reply from the function (*struct). - Error error // After completion, the error status. - Done chan *Call // Strobes when call is complete. -} - -// Client represents an RPC Client. -// There may be multiple outstanding Calls associated -// with a single Client, and a Client may be used by -// multiple goroutines simultaneously. type Client struct { - codec ClientCodec + blocalhost bool + network.TCPClient + conn *network.TCPConn - reqMutex sync.Mutex // protects following - request Request - - mutex sync.Mutex // protects following - seq uint64 - pending map[uint64]*Call - closing bool // user has called Close - shutdown bool // server has told us to stop - bPipe bool + pendingLock sync.RWMutex + startSeq uint64 + pending map[uint64]*Call } -// A ClientCodec implements writing of RPC requests and -// reading of RPC responses for the client side of an RPC session. -// The client calls WriteRequest to write a request to the connection -// and calls ReadResponseHeader and ReadResponseBody in pairs -// to read responses. The client calls Close when finished with the -// connection. ReadResponseBody may be called with a nil -// argument to force the body of the response to be read and then -// discarded. -// See NewClient's comment for information about concurrent access. -type ClientCodec interface { - WriteRequest(*Request, interface{}) error - ReadResponseHeader(*Response) error - ReadResponseBody(interface{}) error - - Close() error +func (slf *Client) NewClientAgent(conn *network.TCPConn) network.Agent { + slf.conn = conn + return slf } -func (client *Client) IsClosed() bool { - client.reqMutex.Lock() - defer client.reqMutex.Unlock() - return client.shutdown || client.closing -} - -func (client *Client) send(call *Call, queueMode bool) { - client.reqMutex.Lock() - defer client.reqMutex.Unlock() - - // Register this call. - client.mutex.Lock() - if client.shutdown || client.closing { - client.mutex.Unlock() - call.Error = ErrShutdown - call.done() - return +func (slf *Client) Connect(addr string) error { + slf.Addr = addr + if strings.Index(addr,"localhost") == 0 { + slf.blocalhost = true + return nil } - seq := client.seq - client.seq++ - client.pending[seq] = call - client.mutex.Unlock() + slf.ConnNum = 1 + slf.ConnectInterval = time.Second*2 + slf.PendingWriteNum = 10000 + slf.AutoReconnect = true + slf.LenMsgLen =2 + slf.MinMsgLen = 2 + slf.MaxMsgLen = math.MaxUint16 + slf.NewAgent =slf.NewClientAgent + slf.LittleEndian = LittleEndian - // Encode and send the request. - client.request.Seq = seq - client.request.ServiceMethod = call.ServiceMethod - client.request.QueueMode = queueMode - err := client.codec.WriteRequest(&client.request, call.Args) - if err != nil { - client.mutex.Lock() - call = client.pending[seq] - delete(client.pending, seq) - client.mutex.Unlock() - if call != nil { - call.Error = err - call.done() - } + slf.pendingLock.Lock() + for _,v := range slf.pending { + v.Err = fmt.Errorf("node is disconnect.") + v.done <- v } + slf.pending = map[uint64]*Call{} + slf.pendingLock.Unlock() + slf.Start() + return nil } -func (client *Client) input() { - var err error - var response Response - for err == nil { - response = Response{} - err = client.codec.ReadResponseHeader(&response) - if err != nil { - break - } - seq := response.Seq - client.mutex.Lock() - call := client.pending[seq] - delete(client.pending, seq) - client.mutex.Unlock() - - switch { - case call == nil: - // We've got no pending call. That usually means that - // WriteRequest partially failed, and call was already - // removed; response is a server telling us about an - // error reading request body. We should still attempt - // to read error body, but there's no one to give it to. - err = client.codec.ReadResponseBody(nil) - if err != nil { - err = errors.New("reading error body: " + err.Error()) - } - case response.Error != "": - // We've got an error response. Give this to the request; - // any subsequent requests will get the ReadResponseBody - // error if there is one. - call.Error = ServerError(response.Error) - err = client.codec.ReadResponseBody(nil) - if err != nil { - err = errors.New("reading error body: " + err.Error()) - } - call.done() - default: - err = client.codec.ReadResponseBody(call.Reply) - if err != nil { - call.Error = errors.New("reading body " + err.Error()) - } - if client.bPipe { - err = nil - } - call.done() - } - } - // Terminate pending calls. - client.reqMutex.Lock() - client.mutex.Lock() - client.shutdown = true - closing := client.closing - if err == io.EOF { - if closing { - err = ErrShutdown - } else { - err = io.ErrUnexpectedEOF - } - } - for _, call := range client.pending { - call.Error = err - call.done() - } - client.mutex.Unlock() - client.reqMutex.Unlock() - if debugLog && err != io.EOF && !closing { - log.Println("rpc: client protocol error:", err) - } -} - -func (call *Call) done() { - select { - case call.Done <- call: - // ok - default: - // We don't want to block here. It is the caller's responsibility to make - // sure the channel has enough buffer space. See comment in Go(). - if debugLog { - log.Println("rpc: discarding Call reply due to insufficient Done chan capacity") - } - } -} - -// NewClient returns a new Client to handle requests to the -// set of services at the other end of the connection. -// It adds a buffer to the write side of the connection so -// the header and payload are sent as a unit. -// -// The read and write halves of the connection are serialized independently, -// so no interlocking is required. However each half may be accessed -// concurrently so the implementation of conn should protect against -// concurrent reads or concurrent writes. -func NewClient(conn io.ReadWriteCloser, isPipe bool) *Client { - encBuf := bufio.NewWriter(conn) - client := &gobClientCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(encBuf), encBuf} - return NewClientWithCodec(client, isPipe) -} - -// NewClientWithCodec is like NewClient but uses the specified -// codec to encode requests and decode responses. -func NewClientWithCodec(codec ClientCodec, isPipe bool) *Client { - client := &Client{ - codec: codec, - pending: make(map[uint64]*Call), - bPipe: isPipe, - } - go client.input() - return client -} - -type gobClientCodec struct { - rwc io.ReadWriteCloser - dec *gob.Decoder - enc *gob.Encoder - encBuf *bufio.Writer -} - -func (c *gobClientCodec) WriteRequest(r *Request, body interface{}) (err error) { - if err = c.enc.Encode(r); err != nil { - return - } - if err = c.enc.Encode(body); err != nil { - return - } - return c.encBuf.Flush() -} - -func (c *gobClientCodec) ReadResponseHeader(r *Response) error { - return c.dec.Decode(r) -} - -func (c *gobClientCodec) ReadResponseBody(body interface{}) error { - return c.dec.Decode(body) -} - -func (c *gobClientCodec) Close() error { - return c.rwc.Close() -} - -// DialHTTP connects to an HTTP RPC server at the specified network address -// listening on the default HTTP RPC path. -func DialHTTP(network, address string) (*Client, error) { - return DialHTTPPath(network, address, DefaultRPCPath) -} - -// DialHTTPPath connects to an HTTP RPC server -// at the specified network address and path. -func DialHTTPPath(network, address, path string) (*Client, error) { - var err error - conn, err := net.Dial(network, address) - - if err != nil { - return nil, err - } - tcpconn, _ := conn.(*net.TCPConn) - tcpconn.SetNoDelay(true) - - io.WriteString(conn, "CONNECT "+path+" HTTP/1.0\n\n") - - // Require successful HTTP response - // before switching to RPC protocol. - resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "CONNECT"}) - if err == nil && resp.Status == connected { - return NewClient(conn, false), nil - } - if err == nil { - err = errors.New("unexpected HTTP response: " + resp.Status) - } - conn.Close() - return nil, &net.OpError{ - Op: "dial-http", - Net: network + " " + address, - Addr: nil, - Err: err, - } -} - -// Dial connects to an RPC server at the specified network address. -func Dial(network, address string) (*Client, error) { - conn, err := net.Dial(network, address) - if err != nil { - return nil, err - } - tcpconn, _ := conn.(*net.TCPConn) - tcpconn.SetNoDelay(true) - return NewClient(conn, false), nil -} - -func DialTimeOut(network, address string, timeout time.Duration) (*Client, error) { - conn, err := net.DialTimeout(network, address, timeout) - if err != nil { - return nil, err - } - tcpconn, _ := conn.(*net.TCPConn) - tcpconn.SetNoDelay(true) - return NewClient(conn, false), nil -} - -// Close calls the underlying codec's Close method. If the connection is already -// shutting down, ErrShutdown is returned. -func (client *Client) Close() error { - client.mutex.Lock() - if client.closing { - client.mutex.Unlock() - return ErrShutdown - } - client.closing = true - client.mutex.Unlock() - return client.codec.Close() -} - -// Go invokes the function asynchronously. It returns the Call structure representing -// the invocation. The done channel will signal when the call is complete by returning -// the same Call object. If done is nil, Go will allocate a new channel. -// If non-nil, done must be buffered or Go will deliberately crash. -func (client *Client) Go(serviceMethod string, args interface{}, reply interface{}, done chan *Call, queueMode bool) *Call { +func (slf *Client) AsycGo(rpcHandler IRpcHandler,mutiCoroutine bool,serviceMethod string,callback reflect.Value, args interface{},replyParam interface{}) error { call := new(Call) - call.ServiceMethod = serviceMethod - call.Args = args - call.Reply = reply - if done == nil { - done = make(chan *Call, 10) // buffered. - } else { - // If caller passes done != nil, it must arrange that - // done has enough buffer for the number of simultaneous - // RPCs that will be using that channel. If the channel - // is totally unbuffered, it's best not to run at all. - if cap(done) == 0 { - log.Panic("rpc: done channel is unbuffered") - } + call.Reply = replyParam + call.callback = &callback + call.rpcHandler = rpcHandler + + request := &RpcRequest{} + request.NoReply = false + request.MutiCoroutine = mutiCoroutine + call.Arg = args + slf.pendingLock.Lock() + slf.startSeq += 1 + call.Seq = slf.startSeq + request.Seq = slf.startSeq + slf.pending[call.Seq] = call + slf.pendingLock.Unlock() + + request.ServiceMethod = serviceMethod + var herr error + request.InParam,herr = processor.Marshal(args) + if herr != nil { + return herr } - call.Done = done - client.send(call, queueMode) + + bytes,err := processor.Marshal(request) + if err != nil { + return err + } + if slf.conn == nil { + return fmt.Errorf("Rpc server is disconnect,call %s is fail!",serviceMethod) + } + err = slf.conn.WriteMsg(bytes) + if err != nil { + call.Err = err + } + + return call.Err +} + +func (slf *Client) Go(noReply bool,mutiCoroutine bool,serviceMethod string, args interface{},reply interface{}) *Call { + call := new(Call) + call.done = make(chan *Call,1) + call.Reply = reply + + request := &RpcRequest{} + request.MutiCoroutine = mutiCoroutine + request.NoReply = noReply + call.Arg = args + slf.pendingLock.Lock() + slf.startSeq += 1 + call.Seq = slf.startSeq + request.Seq = slf.startSeq + slf.pending[call.Seq] = call + slf.pendingLock.Unlock() + + request.ServiceMethod = serviceMethod + var herr error + request.InParam,herr = processor.Marshal(args) + if herr != nil { + call.Err = herr + return call + } + + bytes,err := processor.Marshal(request) + if err != nil { + call.Err = err + return call + } + + err = slf.conn.WriteMsg(bytes) + if err != nil { + call.Err = err + } + return call } -// Call invokes the named function, waits for it to complete, and returns its error status. -func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error { - select { - case call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1), false).Done: - return call.Error - case <-time.After(30 * time.Second): +type RequestHandler func(Returns interface{},Err error) + +type RpcRequest struct { + //packhead + Seq uint64 // sequence number chosen by client + ServiceMethod string // format: "Service.Method" + NoReply bool //是否需要返回 + MutiCoroutine bool // 是否多协程模式 + + //packbody + InParam []byte + localReply interface{} + localParam interface{} //本地调用的参数列表 + requestHandle RequestHandler + + callback *reflect.Value +} + +type RpcResponse struct { + //head + Seq uint64 // sequence number chosen by client + Err error + + //returns + Returns []byte +} + + +func (slf *Client) Run(){ + for { + bytes,err := slf.conn.ReadMsg() + if err != nil { + slf.Close() + slf.Start() + } + //1.解析head + respone := &RpcResponse{} + err = processor.Unmarshal(bytes,respone) + if err != nil { + log.Error("rpcClient Unmarshal head error,error:%+v",err) + continue + } + + slf.pendingLock.Lock() + v,ok := slf.pending[respone.Seq] + if ok == false { + log.Error("rpcClient cannot find seq %d in pending",respone.Seq) + slf.pendingLock.Unlock() + }else { + delete(slf.pending,respone.Seq) + slf.pendingLock.Unlock() + + err = processor.Unmarshal(respone.Returns,v.Reply) + if err != nil { + log.Error("rpcClient Unmarshal body error,error:%+v",err) + continue + } + + if v.callback.IsValid() { + v.rpcHandler.(*RpcHandler).callResponeCallBack<-v + }else{ + //发送至接受者 + v.done <- v + } + + } } - //call := <-client.Go(serviceMethod, args, reply, make(chan *Call, 1)).Done - return errors.New(fmt.Sprintf("Call RPC %s is time out 30s", serviceMethod)) } + +func (slf *Client) OnClose(){ + if slf.blocalhost== false{ + //关闭时,重新连接 + slf.Start() + } +} \ No newline at end of file diff --git a/rpc/debug.go b/rpc/debug.go deleted file mode 100644 index a1d799f..0000000 --- a/rpc/debug.go +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rpc - -/* - Some HTML presented at http://machine:port/debug/rpc - Lists services, their methods, and some statistics, still rudimentary. -*/ - -import ( - "fmt" - "html/template" - "net/http" - "sort" -) - -const debugText = ` - - Services - {{range .}} - - Service {{.Name}} - - - MethodCalls - {{range .Method}} - - {{.Name}}({{.Type.ArgType}}, {{.Type.ReplyType}}) error - {{.Type.NumCalls}} - - {{end}} - - {{end}} - - ` - -var debug = template.Must(template.New("RPC debug").Parse(debugText)) - -// If set, print log statements for internal and I/O errors. -var debugLog = false - -type debugMethod struct { - Type *methodType - Name string -} - -type methodArray []debugMethod - -type debugService struct { - Service *service - Name string - Method methodArray -} - -type serviceArray []debugService - -func (s serviceArray) Len() int { return len(s) } -func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func (m methodArray) Len() int { return len(m) } -func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name } -func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] } - -type debugHTTP struct { - *Server -} - -// Runs at /debug/rpc -func (server debugHTTP) ServeHTTP(w http.ResponseWriter, req *http.Request) { - // Build a sorted version of the data. - var services serviceArray - server.serviceMap.Range(func(snamei, svci interface{}) bool { - svc := svci.(*service) - ds := debugService{svc, snamei.(string), make(methodArray, 0, len(svc.method))} - for mname, method := range svc.method { - ds.Method = append(ds.Method, debugMethod{method, mname}) - } - sort.Sort(ds.Method) - services = append(services, ds) - return true - }) - sort.Sort(services) - err := debug.Execute(w, services) - if err != nil { - fmt.Fprintln(w, "rpc: error executing template:", err.Error()) - } -} diff --git a/rpc/gobrpc/processor.go b/rpc/gobrpc/processor.go new file mode 100644 index 0000000..0272095 --- /dev/null +++ b/rpc/gobrpc/processor.go @@ -0,0 +1 @@ +package gobrpc diff --git a/rpc/jsonprocessor.go b/rpc/jsonprocessor.go new file mode 100644 index 0000000..2539171 --- /dev/null +++ b/rpc/jsonprocessor.go @@ -0,0 +1,22 @@ +package rpc + +import ( + + "encoding/json" + +) + +type JsonProcessor struct { +} + + + +func (slf *JsonProcessor) Marshal(v interface{}) ([]byte, error){ + return json.Marshal(v) +} + +func (slf *JsonProcessor) Unmarshal(data []byte, v interface{}) error{ + + return json.Unmarshal(data,v) +} + diff --git a/rpc/netrpc.go b/rpc/netrpc.go new file mode 100644 index 0000000..9ab1e3e --- /dev/null +++ b/rpc/netrpc.go @@ -0,0 +1 @@ +package rpc diff --git a/rpc/rpchandler.go b/rpc/rpchandler.go new file mode 100644 index 0000000..f9f7a29 --- /dev/null +++ b/rpc/rpchandler.go @@ -0,0 +1,377 @@ +package rpc + +import ( + "fmt" + "github.com/duanhf2012/originnet/log" + "reflect" + "strings" + "unicode" + "unicode/utf8" +) + +type FuncRpcClient func(serviceMethod string) ([]*Client,error) +type FuncRpcServer func() (*Server) +var NilError = reflect.Zero(reflect.TypeOf((*error)(nil)).Elem()) + +type RpcMethodInfo struct { + method reflect.Method + iparam interface{} + oParam reflect.Value +} + +type RpcHandler struct { + callRequest chan *RpcRequest + rpcHandler IRpcHandler + mapfunctons map[string]RpcMethodInfo + funcRpcClient FuncRpcClient + funcRpcServer FuncRpcServer + + callResponeCallBack chan *Call //异步返回的回调 +} + +type IRpcHandler interface { + GetName() string + InitRpcHandler(rpcHandler IRpcHandler,getClientFun FuncRpcClient,getServerFun FuncRpcServer) + GetRpcHandler() IRpcHandler + PushRequest(callinfo *RpcRequest) + HandlerRpcRequest(request *RpcRequest) + HandlerRpcResponeCB(call *Call) + + GetRpcRequestChan() chan *RpcRequest + GetRpcResponeChan() chan *Call + CallMethod(ServiceMethod string,param interface{},reply interface{}) error +} + +func (slf *RpcHandler) GetRpcHandler() IRpcHandler{ + return slf.rpcHandler +} + +func (slf *RpcHandler) InitRpcHandler(rpcHandler IRpcHandler,getClientFun FuncRpcClient,getServerFun FuncRpcServer) { + slf.callRequest = make(chan *RpcRequest,100000) + slf.callResponeCallBack = make(chan *Call,100000) + + slf.rpcHandler = rpcHandler + slf.mapfunctons = map[string]RpcMethodInfo{} + slf.funcRpcClient = getClientFun + slf.funcRpcServer = getServerFun + + slf.RegisterRpc(rpcHandler) +} + +// Is this an exported - upper case - name? +func isExported(name string) bool { + rune, _ := utf8.DecodeRuneInString(name) + return unicode.IsUpper(rune) +} + +// Is this type exported or a builtin? +func (slf *RpcHandler) isExportedOrBuiltinType(t reflect.Type) bool { + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + // PkgPath will be non-empty even for an exported type, + // so we need to check the type name as well. + return isExported(t.Name()) || t.PkgPath() == "" +} + + +func (slf *RpcHandler) suitableMethods(method reflect.Method) error { + //只有RPC_开头的才能被调用 + if strings.Index(method.Name,"RPC_")!=0 { + return nil + } + + //取出输入参数类型 + var rpcMethodInfo RpcMethodInfo + typ := method.Type + if typ.NumOut() != 1 { + return fmt.Errorf("%s The number of returned arguments must be 1!",method.Name) + } + + if typ.Out(0).String() != "error" { + return fmt.Errorf("%s The return parameter must be of type error!",method.Name) + } + + if typ.NumIn() != 3 { + return fmt.Errorf("%s The number of input arguments must be 1!",method.Name) + } + + if slf.isExportedOrBuiltinType(typ.In(1)) == false || slf.isExportedOrBuiltinType(typ.In(2)) == false { + return fmt.Errorf("%s Unsupported parameter types!",method.Name) + } + + rpcMethodInfo.iparam = reflect.New(typ.In(1).Elem()).Interface() //append(rpcMethodInfo.iparam,) + rpcMethodInfo.oParam = reflect.New(typ.In(2).Elem()) + + rpcMethodInfo.method = method + slf.mapfunctons[slf.rpcHandler.GetName()+"."+method.Name] = rpcMethodInfo + return nil +} + +func (slf *RpcHandler) RegisterRpc(rpcHandler IRpcHandler) error { + typ := reflect.TypeOf(rpcHandler) + for m:=0;m 1 { + log.Error("Cannot call more then 1 node!") + return fmt.Errorf("Cannot call more then 1 node!") + } + + //2.rpcclient调用 + //如果调用本结点服务 + pClient := pClientList[0] + if pClient.blocalhost == true { + pLocalRpcServer:=slf.funcRpcServer() + //判断是否是同一服务 + sMethod := strings.Split(serviceMethod,".") + if len(sMethod)!=2 { + err := fmt.Errorf("Call serviceMethod %s is error!",serviceMethod) + log.Error("%+v",err) + return err + } + //调用自己rpcHandler处理器 + if sMethod[0] == slf.rpcHandler.GetName() { //自己服务调用 + // + return pLocalRpcServer.myselfRpcHandlerGo(sMethod[0],sMethod[1],args,nil) + } + //其他的rpcHandler的处理器 + pCall := pLocalRpcServer.rpcHandlerGo(true,mutiCoroutine,sMethod[0],sMethod[1],args,nil) + return pCall.Err + } + + //跨node调用 + pCall := pClient.Go(true,mutiCoroutine,serviceMethod,args,nil) + return pCall.Err +} + +func (slf *RpcHandler) callRpc(serviceMethod string,mutiCoroutine bool,args interface{},reply interface{}) error { + pClientList,err := slf.funcRpcClient(serviceMethod) + if err != nil { + log.Error("Call serviceMethod is error:%+v!",err) + return err + } + if len(pClientList) > 1 { + log.Error("Cannot call more then 1 node!") + return fmt.Errorf("Cannot call more then 1 node!") + } + + //2.rpcclient调用 + //如果调用本结点服务 + pClient := pClientList[0] + if pClient.blocalhost == true { + pLocalRpcServer:=slf.funcRpcServer() + //判断是否是同一服务 + sMethod := strings.Split(serviceMethod,".") + if len(sMethod)!=2 { + err := fmt.Errorf("Call serviceMethod %s is error!",serviceMethod) + log.Error("%+v",err) + return err + } + //调用自己rpcHandler处理器 + if sMethod[0] == slf.rpcHandler.GetName() { //自己服务调用 + // + return pLocalRpcServer.myselfRpcHandlerGo(sMethod[0],sMethod[1],args,reply) + } + //其他的rpcHandler的处理器 + pCall := pLocalRpcServer.rpcHandlerGo(false,mutiCoroutine,sMethod[0],sMethod[1],args,reply) + pResult := pCall.Done() + return pResult.Err + } + + //跨node调用 + pCall := pClient.Go(false,mutiCoroutine,serviceMethod,args,reply) + pResult := pCall.Done() + return pResult.Err +} + +func (slf *RpcHandler) asyncCallRpc(serviceMethod string,mutiCoroutine bool,args interface{},callback interface{}) error { + fVal := reflect.ValueOf(callback) + if fVal.Kind()!=reflect.Func{ + return fmt.Errorf("input function is error!") + } + + reply := reflect.New(fVal.Type().In(0).Elem()).Interface() + pClientList,err := slf.funcRpcClient(serviceMethod) + if err != nil { + log.Error("Call serviceMethod is error:%+v!",err) + return err + } + if len(pClientList) > 1 { + log.Error("Cannot call more then 1 node!") + return fmt.Errorf("Cannot call more then 1 node!") + } + + //2.rpcclient调用 + //如果调用本结点服务 + pClient := pClientList[0] + if pClient.blocalhost == true { + pLocalRpcServer:=slf.funcRpcServer() + //判断是否是同一服务 + sMethod := strings.Split(serviceMethod,".") + if len(sMethod)!=2 { + err := fmt.Errorf("Call serviceMethod %s is error!",serviceMethod) + log.Error("%+v",err) + return err + } + //调用自己rpcHandler处理器 + if sMethod[0] == slf.rpcHandler.GetName() { //自己服务调用 + err := pLocalRpcServer.myselfRpcHandlerGo(sMethod[0],sMethod[1],args,reply) + if err == nil { + fVal.Call([]reflect.Value{reflect.ValueOf(reply),NilError}) + }else{ + fVal.Call([]reflect.Value{reflect.ValueOf(reply),reflect.ValueOf(err)}) + } + + } + + //其他的rpcHandler的处理器 + if callback!=nil { + return pLocalRpcServer.rpcHandlerAsyncGo(slf,false,mutiCoroutine,sMethod[0],sMethod[1],args,reply,fVal) + } + pCall := pLocalRpcServer.rpcHandlerGo(false,mutiCoroutine,sMethod[0],sMethod[1],args,reply) + pResult := pCall.Done() + return pResult.Err + } + + //跨node调用 + return pClient.AsycGo(slf,mutiCoroutine,serviceMethod,fVal,args,reply) +} + +func (slf *RpcHandler) GetName() string{ + return slf.rpcHandler.GetName() +} + + +//func (slf *RpcHandler) asyncCallRpc(serviceMethod string,mutiCoroutine bool,callback interface{},args ...interface{}) error { +//func (slf *RpcHandler) callRpc(serviceMethod string,reply interface{},mutiCoroutine bool,args ...interface{}) error { +//func (slf *RpcHandler) goRpc(serviceMethod string,mutiCoroutine bool,args ...interface{}) error { +//(reply *int,err error) {} +func (slf *RpcHandler) AsyncCall(serviceMethod string,args interface{},callback interface{}) error { + return slf.asyncCallRpc(serviceMethod,false,args,callback) +} + +func (slf *RpcHandler) GRAsyncCall(serviceMethod string,args interface{},callback interface{}) error { + return slf.asyncCallRpc(serviceMethod,true,args,callback) +} + +func (slf *RpcHandler) Call(serviceMethod string,args interface{},reply interface{}) error { + return slf.callRpc(serviceMethod,false,args,reply) +} + +func (slf *RpcHandler) GRCall(serviceMethod string,args interface{},reply interface{}) error { + return slf.callRpc(serviceMethod,true,args,reply) +} + +func (slf *RpcHandler) Go(serviceMethod string,args interface{}) error { + return slf.goRpc(serviceMethod,false,args) +} + +func (slf *RpcHandler) GRGo(serviceMethod string,args interface{}) error { + return slf.goRpc(serviceMethod,true,args) +} \ No newline at end of file diff --git a/rpc/server.go b/rpc/server.go index 4f8e4f3..afe34e4 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -1,849 +1,260 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -/* - Package rpc provides access to the exported methods of an object across a - network or other I/O connection. A server registers an object, making it visible - as a service with the name of the type of the object. After registration, exported - methods of the object will be accessible remotely. A server may register multiple - objects (services) of different types but it is an error to register multiple - objects of the same type. - - Only methods that satisfy these criteria will be made available for remote access; - other methods will be ignored: - - - the method's type is exported. - - the method is exported. - - the method has two arguments, both exported (or builtin) types. - - the method's second argument is a pointer. - - the method has return type error. - - In effect, the method must look schematically like - - func (t *T) MethodName(argType T1, replyType *T2) error - - where T1 and T2 can be marshaled by encoding/gob. - These requirements apply even if a different codec is used. - (In the future, these requirements may soften for custom codecs.) - - The method's first argument represents the arguments provided by the caller; the - second argument represents the result parameters to be returned to the caller. - The method's return value, if non-nil, is passed back as a string that the client - sees as if created by errors.New. If an error is returned, the reply parameter - will not be sent back to the client. - - The server may handle requests on a single connection by calling ServeConn. More - typically it will create a network listener and call Accept or, for an HTTP - listener, HandleHTTP and http.Serve. - - A client wishing to use the service establishes a connection and then invokes - NewClient on the connection. The convenience function Dial (DialHTTP) performs - both steps for a raw network connection (an HTTP connection). The resulting - Client object has two methods, Call and Go, that specify the service and method to - call, a pointer containing the arguments, and a pointer to receive the result - parameters. - - The Call method waits for the remote call to complete while the Go method - launches the call asynchronously and signals completion using the Call - structure's Done channel. - - Unless an explicit codec is set up, package encoding/gob is used to - transport the data. - - Here is a simple example. A server wishes to export an object of type Arith: - - package server - - import "errors" - - type Args struct { - A, B int - } - - type Quotient struct { - Quo, Rem int - } - - type Arith int - - func (t *Arith) Multiply(args *Args, reply *int) error { - *reply = args.A * args.B - return nil - } - - func (t *Arith) Divide(args *Args, quo *Quotient) error { - if args.B == 0 { - return errors.New("divide by zero") - } - quo.Quo = args.A / args.B - quo.Rem = args.A % args.B - return nil - } - - The server calls (for HTTP service): - - arith := new(Arith) - rpc.Register(arith) - rpc.HandleHTTP() - l, e := net.Listen("tcp", ":1234") - if e != nil { - log.Fatal("listen error:", e) - } - go http.Serve(l, nil) - - At this point, clients can see a service "Arith" with methods "Arith.Multiply" and - "Arith.Divide". To invoke one, a client first dials the server: - - client, err := rpc.DialHTTP("tcp", serverAddress + ":1234") - if err != nil { - log.Fatal("dialing:", err) - } - - Then it can make a remote call: - - // Synchronous call - args := &server.Args{7,8} - var reply int - err = client.Call("Arith.Multiply", args, &reply) - if err != nil { - log.Fatal("arith error:", err) - } - fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply) - - or - - // Asynchronous call - quotient := new(Quotient) - divCall := client.Go("Arith.Divide", args, quotient, nil) - replyCall := <-divCall.Done // will be equal to divCall - // check errors, print, etc. - - A server implementation will often provide a simple, type-safe wrapper for the - client. - - The net/rpc package is frozen and is not accepting new features. -*/ package rpc import ( - "bufio" - "encoding/gob" - "errors" "fmt" - "io" - "log" + "github.com/duanhf2012/originnet/log" + "github.com/duanhf2012/originnet/network" + "math" "net" - "net/http" "reflect" "strings" - "sync" - "time" - "unicode" - "unicode/utf8" - - runtimedebug "runtime/debug" - - orginservice "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/util" - "github.com/duanhf2012/origin/util/uuid" ) -const ( - // Defaults used by HandleHTTP - DefaultRPCPath = "/_goRPC_" - DefaultDebugPath = "/debug/rpc" -) +var processor iprocessor = &JsonProcessor{} +var LittleEndian bool -// Precompute the reflect type for error. Can't use error directly -// because Typeof takes an empty interface value. This is annoying. -var typeOfError = reflect.TypeOf((*error)(nil)).Elem() - -type methodType struct { - sync.Mutex // protects counters - method reflect.Method - ArgType reflect.Type - ReplyType reflect.Type - numCalls uint +type Call struct { + Seq uint64 + //ServiceMethod string + Arg interface{} + Reply interface{} + Respone *RpcResponse + Err error + done chan *Call // Strobes when call is complete. + connid int + callback *reflect.Value + rpcHandler IRpcHandler } -type service struct { - name string // name of service - rcvr reflect.Value // receiver of methods for the service - typ reflect.Type // type of the receiver - method map[string]*methodType // registered methods +func (slf *Call) Done() *Call{ + return <-slf.done } -// Request is a header written before every RPC call. It is used internally -// but documented here as an aid to debugging, such as when analyzing -// network traffic. -type Request struct { - ServiceMethod string // format: "Service.Method" - Seq uint64 // sequence number chosen by client - next *Request // for free list in Server - QueueMode bool +type iprocessor interface { + Marshal(v interface{}) ([]byte, error) + Unmarshal(data []byte, v interface{}) error } -// Response is a header written before every RPC return. It is used internally -// but documented here as an aid to debugging, such as when analyzing -// network traffic. -type Response struct { - ServiceMethod string // echoes that of the Request - Seq uint64 // echoes that of the request - Error string // error, if any. - next *Response // for free list in Server -} - -const ( - MAX_RPCDATA_QUEUE_COUNT = 10240 -) - -// Server represents an RPC Server. type Server struct { - serviceMap sync.Map // map[string]*service - reqLock sync.Mutex // protects freeReq - freeReq *Request - respLock sync.Mutex // protects freeResp - freeResp *Response + functions map[interface{}]interface{} + listenAddr string //ip:port - mapCallQueue map[string]chan *CQueueRpcData + cmdchannel chan *Call + + rpcHandleFinder RpcHandleFinder + rpcserver *network.TCPServer } -type CQueueRpcData struct { - server *Server - sending *sync.Mutex - wg *sync.WaitGroup - mtype *methodType - req *Request - argv reflect.Value - replyv reflect.Value - codec ServerCodec - service *service +type RpcHandleFinder interface { + FindRpcHandler(serviceMethod string) IRpcHandler } -// NewServer returns a new Server. -func NewServer() *Server { - server := &Server{} - server.mapCallQueue = make(map[string]chan *CQueueRpcData) - - return server +func (slf *Server) Init(rpcHandleFinder RpcHandleFinder) { + slf.cmdchannel = make(chan *Call,10000) + slf.rpcHandleFinder = rpcHandleFinder + slf.rpcserver = &network.TCPServer{} } -// DefaultServer is the default instance of *Server. -var DefaultServer = NewServer() - -// Is this an exported - upper case - name? -func isExported(name string) bool { - rune, _ := utf8.DecodeRuneInString(name) - return unicode.IsUpper(rune) +func (slf *Server) Start(listenAddr string) { + slf.listenAddr = listenAddr + slf.rpcserver.Addr = listenAddr + slf.rpcserver.LenMsgLen = 2 //uint16 + slf.rpcserver.MinMsgLen = 2 + slf.rpcserver.MaxMsgLen = math.MaxUint16 + slf.rpcserver.MaxConnNum = 10000 + slf.rpcserver.PendingWriteNum = 10000 + slf.rpcserver.NewAgent =slf.NewAgent + slf.rpcserver.LittleEndian = LittleEndian + slf.rpcserver.Start() } -// Is this type exported or a builtin? -func isExportedOrBuiltinType(t reflect.Type) bool { - for t.Kind() == reflect.Ptr { - t = t.Elem() - } - // PkgPath will be non-empty even for an exported type, - // so we need to check the type name as well. - return isExported(t.Name()) || t.PkgPath() == "" + +func (gate *RpcAgent) OnDestroy() {} + +type RpcAgent struct { + conn network.Conn + rpcserver *Server + userData interface{} } -// Register publishes in the server the set of methods of the -// receiver value that satisfy the following conditions: -// - exported method of exported type -// - two arguments, both of exported type -// - the second argument is a pointer -// - one return value, of type error -// It returns an error if the receiver is not an exported type or has -// no suitable methods. It also logs the error using package log. -// The client accesses each method using a string of the form "Type.Method", -// where Type is the receiver's concrete type. -func (server *Server) Register(rcvr interface{}) error { - return server.register(rcvr, "", "", false) +type RpcRequestRw struct { + // + ServiceMethod string // format: "Service.Method" + //Seq uint64 // sequence number chosen by client + InputParam []byte + + requestHandle RequestHandler } -// RegisterName is like Register but uses the provided name for the type -// instead of the receiver's concrete type. -func (server *Server) RegisterName(name string, prefix string, rcvr interface{}) error { - return server.register(rcvr, name, prefix, true) -} - -func (server *Server) ProcessQueue(name string) { - chanRpc, ok := server.mapCallQueue[name] - if ok == false { - orginservice.GetLogger().Printf(orginservice.LEVER_FATAL, "cannot find queue") - return - } - - //定时报告队列超负荷运行 - var checktm util.Timer - checktm.SetupTimerEx(time.Minute*1) - - maxSize := 0 - uuidkey := uuid.Rand().HexEx() +func (agent *RpcAgent) Run() { for { - if checktm.CheckTimeOut() { - orginservice.GetLogger().Printf(orginservice.LEVER_WARN, "RpcServer.ProcessQueue(%s) max %d",name,maxSize) - maxSize = 0 - }else { - curSize := len(chanRpc) - if curSize > maxSize { - maxSize = curSize - } - } - - rpcData := <-chanRpc - - - orginservice.MonitorEnter(uuidkey,name) - rpcData.service.call(rpcData.server, rpcData.sending, rpcData.wg, rpcData.mtype, rpcData.req, rpcData.argv, rpcData.replyv, rpcData.codec) - orginservice.MonitorLeave(uuidkey) - } -} - -func (server *Server) register(rcvr interface{}, name string, prefix string, useName bool) error { - s := new(service) - s.typ = reflect.TypeOf(rcvr) - s.rcvr = reflect.ValueOf(rcvr) - sname := reflect.Indirect(s.rcvr).Type().Name() - - _, ok := server.mapCallQueue[sname] - if ok == false { - server.mapCallQueue[sname] = make(chan *CQueueRpcData, 10240) - util.GoRecover(server.ProcessQueue,-1, sname) - } - if useName { - sname = name - } - if sname == "" { - s := "rpc.Register: no service name for type " + s.typ.String() - log.Print(s) - return errors.New(s) - } - - if !isExported(sname) && !useName { - s := "rpc.Register: type " + sname + " is not exported" - log.Print(s) - return errors.New(s) - } - s.name = sname - - // Install the methods - s.method = suitableMethods(prefix, s.typ, true) - - if len(s.method) == 0 { - str := "" - - // To help the user, see if a pointer receiver would work. - method := suitableMethods(prefix, reflect.PtrTo(s.typ), false) - if len(method) != 0 { - str = "rpc.Register: type " + sname + " has no exported methods of suitable type (hint: pass a pointer to value of that type)" - } else { - str = "rpc.Register: type " + sname + " has no exported methods of suitable type" - } - //log.Print(str) - - return errors.New(str) - } - - //将已经注册的消息加载 - svci, ok := server.serviceMap.Load(sname) - if ok { - svc := svci.(*service) - for key, value := range svc.method { - s.method[key] = &methodType{method: value.method, ArgType: value.ArgType, ReplyType: value.ReplyType} - } - } - - server.serviceMap.Store(sname, s) - return nil -} - -// suitableMethods returns suitable Rpc methods of typ, it will report -// error using log if reportErr is true. -func suitableMethods(prefix string, typ reflect.Type, reportErr bool) map[string]*methodType { - methods := make(map[string]*methodType) - for m := 0; m < typ.NumMethod(); m++ { - method := typ.Method(m) - mtype := method.Type - mname := method.Name - - if prefix != "" { - if strings.Contains(mname, prefix) == false { - continue - } - } - - // Method must be exported. - if method.PkgPath != "" { - continue - } - // Method needs three ins: receiver, *args, *reply. - if mtype.NumIn() != 3 { - if reportErr { - log.Printf("rpc.Register: method %q has %d input parameters; needs exactly three\n", mname, mtype.NumIn()) - } - continue - } - // First arg need not be a pointer. - argType := mtype.In(1) - if !isExportedOrBuiltinType(argType) { - if reportErr { - log.Printf("rpc.Register: argument type of method %q is not exported: %q\n", mname, argType) - } - continue - } - // Second arg must be a pointer. - replyType := mtype.In(2) - if replyType.Kind() != reflect.Ptr { - if reportErr { - log.Printf("rpc.Register: reply type of method %q is not a pointer: %q\n", mname, replyType) - } - continue - } - // Reply type must be exported. - if !isExportedOrBuiltinType(replyType) { - if reportErr { - log.Printf("rpc.Register: reply type of method %q is not exported: %q\n", mname, replyType) - } - continue - } - // Method needs one out. - if mtype.NumOut() != 1 { - if reportErr { - log.Printf("rpc.Register: method %q has %d output parameters; needs exactly one\n", mname, mtype.NumOut()) - } - continue - } - // The return type of the method must be error. - if returnType := mtype.Out(0); returnType != typeOfError { - if reportErr { - log.Printf("rpc.Register: return type of method %q is %q, must be error\n", mname, returnType) - } - continue - } - methods[mname] = &methodType{method: method, ArgType: argType, ReplyType: replyType} - } - return methods -} - -// A value sent as a placeholder for the server's response value when the server -// receives an invalid request. It is never decoded by the client since the Response -// contains an error when it is used. -var invalidRequest = struct{}{} - -func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) { - resp := server.getResponse() - // Encode the response header - resp.ServiceMethod = req.ServiceMethod - if errmsg != "" { - resp.Error = errmsg - reply = invalidRequest - } - resp.Seq = req.Seq - sending.Lock() - err := codec.WriteResponse(resp, reply) - if debugLog && err != nil { - log.Println("rpc: writing response:", err) - } - sending.Unlock() - server.freeResponse(resp) -} - -func (m *methodType) NumCalls() (n uint) { - m.Lock() - n = m.numCalls - m.Unlock() - return n -} - -func (s *service) call(server *Server, sending *sync.Mutex, wg *sync.WaitGroup, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) { - defer func() { - if r := recover(); r != nil { - var coreInfo string - - coreInfo = string(runtimedebug.Stack()) - coreInfo += "\nCore Request RPC Name:" + req.ServiceMethod - coreInfo += "\n" + fmt.Sprintf("Core information is %v\n", r) - orginservice.GetLogger().Printf(orginservice.LEVER_FATAL, coreInfo) - } - }() - - if wg != nil { - defer wg.Done() - } - - mtype.Lock() - mtype.numCalls++ - mtype.Unlock() - function := mtype.method.Func - // Invoke the method, providing a new value for the reply. - returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv}) - // The return value for the method is an error. - errInter := returnValues[0].Interface() - errmsg := "" - if errInter != nil { - errmsg = errInter.(error).Error() - } - server.sendResponse(sending, req, replyv.Interface(), codec, errmsg) - server.freeRequest(req) -} - -type gobServerCodec struct { - rwc io.ReadWriteCloser - dec *gob.Decoder - enc *gob.Encoder - encBuf *bufio.Writer - closed bool -} - -func (c *gobServerCodec) ReadRequestHeader(r *Request) error { - return c.dec.Decode(r) -} - -func (c *gobServerCodec) ReadRequestBody(body interface{}) error { - return c.dec.Decode(body) -} - -func (c *gobServerCodec) WriteResponse(r *Response, body interface{}) (err error) { - if err = c.enc.Encode(r); err != nil { - if c.encBuf.Flush() == nil { - // Gob couldn't encode the header. Should not happen, so if it does, - // shut down the connection to signal that the connection is broken. - log.Println("rpc: gob error encoding response:", err) - c.Close() - } - return - } - if err = c.enc.Encode(body); err != nil { - if c.encBuf.Flush() == nil { - // Was a gob problem encoding the body but the header has been written. - // Shut down the connection to signal that the connection is broken. - log.Println("rpc: gob error encoding body:", err) - c.Close() - } - return - } - return c.encBuf.Flush() -} - -func (c *gobServerCodec) Close() error { - if c.closed { - // Only call c.rwc.Close once; otherwise the semantics are undefined. - return nil - } - c.closed = true - return c.rwc.Close() -} - -// ServeConn runs the server on a single connection. -// ServeConn blocks, serving the connection until the client hangs up. -// The caller typically invokes ServeConn in a go statement. -// ServeConn uses the gob wire format (see package gob) on the -// connection. To use an alternate codec, use ServeCodec. -// See NewClient's comment for information about concurrent access. -func (server *Server) ServeConn(conn io.ReadWriteCloser) { - buf := bufio.NewWriter(conn) - srv := &gobServerCodec{ - rwc: conn, - dec: gob.NewDecoder(conn), - enc: gob.NewEncoder(buf), - encBuf: buf, - } - server.ServeCodec(srv) -} - -// ServeCodec is like ServeConn but uses the specified codec to -// decode requests and encode responses. -func (server *Server) ServeCodec(codec ServerCodec) { - sending := new(sync.Mutex) - wg := new(sync.WaitGroup) - for { - service, mtype, req, argv, replyv, keepReading, queueMode, err := server.readRequest(codec) + data,err := agent.conn.ReadMsg() if err != nil { - if debugLog && err != io.EOF { - orginservice.GetLogger().Printf(orginservice.LEVER_FATAL, "rpc: %v", err) - log.Println("rpc:", err) - } - if !keepReading { - break - } - // send a response if we actually managed to read a header. - if req != nil { - server.sendResponse(sending, req, invalidRequest, codec, err.Error()) - server.freeRequest(req) - } + log.Debug("read message: %v", err) + break + } + + if processor==nil{ + log.Error("Rpc Processor not set!") continue } - rpcData := &CQueueRpcData{server, sending, wg, mtype, req, argv, replyv, codec, service} + var req RpcRequest + //解析head + err = processor.Unmarshal(data,&req) + if err != nil { + log.Debug("processor message: %v", err) + agent.Close() + break + } - if queueMode == true { - rpcChan, ok := server.mapCallQueue[service.name] - if ok == true { - if len(rpcChan) >= MAX_RPCDATA_QUEUE_COUNT { - //不在这里写日志了 否则RPC繁忙 这里会刷日志把磁盘刷爆 ProcessQueue会记录channel繁忙的日志 - //orginservice.GetLogger().Printf(orginservice.LEVER_FATAL, "Rpc Service Name %s chan overload %d", service.name, MAX_RPCDATA_QUEUE_COUNT) - - continue + //交给程序处理 + serviceMethod := strings.Split(req.ServiceMethod,".") + if len(serviceMethod)!=2 { + log.Debug("rpc request req.ServiceMethod is error") + continue + } + rpcHandler := agent.rpcserver.rpcHandleFinder.FindRpcHandler(serviceMethod[0]) + if rpcHandler== nil { + log.Error("service method %s not config!", req.ServiceMethod) + continue + } + if req.NoReply == false { + req.requestHandle = func(Returns interface{},Err error){ + var rpcRespone RpcResponse + rpcRespone.Seq = req.Seq + rpcRespone.Err = Err + if Err==nil { + rpcRespone.Returns,rpcRespone.Err = processor.Marshal(Returns) + } + + bytes,err := processor.Marshal(rpcRespone) + if err != nil { + log.Error("service method %s Marshal error:%+v!", req.ServiceMethod,err) + return + } + + err = agent.conn.WriteMsg(bytes) + if err != nil { + log.Error("Rpc %s return is error:%+v",req.ServiceMethod,err) } - wg.Add(1) - rpcChan <- rpcData - continue - } else { - orginservice.GetLogger().Printf(orginservice.LEVER_FATAL, "Rpc Service Name %s call not find coroutines", service.name) } } - wg.Add(1) - //queueMode - //fmt.Print(queueMode) - util.Go(service.call,server, sending, wg, mtype, req, argv, replyv, codec) - //go service.call(server, sending, wg, mtype, req, argv, replyv, codec) + if req.MutiCoroutine == true { + go rpcHandler.HandlerRpcRequest(&req) + }else{ + rpcHandler.PushRequest(&req) + } + } - // We've seen that there are no more requests. - // Wait for responses to be sent before closing codec. - wg.Wait() - codec.Close() } -// ServeRequest is like ServeCodec but synchronously serves a single request. -// It does not close the codec upon completion. -func (server *Server) ServeRequest(codec ServerCodec) error { - sending := new(sync.Mutex) - service, mtype, req, argv, replyv, keepReading, _, err := server.readRequest(codec) - if err != nil { - if !keepReading { - return err - } - // send a response if we actually managed to read a header. - if req != nil { - server.sendResponse(sending, req, invalidRequest, codec, err.Error()) - server.freeRequest(req) - } +func (agent *RpcAgent) OnClose() { +} + +func (agent *RpcAgent) WriteMsg(msg interface{}) { +} + +func (agent *RpcAgent) LocalAddr() net.Addr { + return agent.conn.LocalAddr() +} + +func (agent *RpcAgent) RemoteAddr() net.Addr { + return agent.conn.RemoteAddr() +} + +func (agent *RpcAgent) Close() { + agent.conn.Close() +} + +func (agent *RpcAgent) Destroy() { + agent.conn.Destroy() +} + + +func (slf *Server) NewAgent(conn *network.TCPConn) network.Agent { + agent := &RpcAgent{conn: conn, rpcserver: slf} + + return agent +} + +func (slf *Server) myselfRpcHandlerGo(handlerName string,methodName string, args interface{},reply interface{}) error { + rpcHandler := slf.rpcHandleFinder.FindRpcHandler(handlerName) + if rpcHandler== nil { + err := fmt.Errorf("service method %s.%s not config!", handlerName,methodName) + log.Error("%s",err.Error()) return err } - service.call(server, sending, nil, mtype, req, argv, replyv, codec) + + return rpcHandler.CallMethod(fmt.Sprintf("%s.%s",handlerName,methodName),args,reply) +} + + +func (slf *Server) rpcHandlerGo(noReply bool,mutiCoroutine bool,handlerName string,methodName string, args interface{},reply interface{}) *Call { + pCall := &Call{} + pCall.done = make( chan *Call,1) + rpcHandler := slf.rpcHandleFinder.FindRpcHandler(handlerName) + if rpcHandler== nil { + pCall.Err = fmt.Errorf("service method %s.%s not config!", handlerName,methodName) + log.Error("%s",pCall.Err.Error()) + pCall.done <- pCall + return pCall + } + var req RpcRequest + req.ServiceMethod = fmt.Sprintf("%s.%s",handlerName,methodName) + req.localParam = args + req.localReply = reply + req.NoReply = noReply + + if noReply == false { + req.requestHandle = func(Returns interface{},Err error){ + pCall.Err = Err + pCall.done <- pCall + } + } + + if mutiCoroutine == true { + go rpcHandler.HandlerRpcRequest(&req) + }else{ + rpcHandler.PushRequest(&req) + } + + return pCall +} + +func (slf *Server) rpcHandlerAsyncGo(callerRpcHandler IRpcHandler,noReply bool,mutiCoroutine bool,handlerName string,methodName string,args interface{},reply interface{},callback reflect.Value) error { + pCall := &Call{} + //pCall.done = make( chan *Call,1) + pCall.rpcHandler = callerRpcHandler + pCall.callback = &callback + rpcHandler := slf.rpcHandleFinder.FindRpcHandler(handlerName) + if rpcHandler== nil { + err := fmt.Errorf("service method %s.%s not config!", handlerName,methodName) + log.Error("%+v",err) + return err + } + + var req RpcRequest + req.ServiceMethod = fmt.Sprintf("%s.%s",handlerName,methodName) + req.localParam = args + req.localReply = reply + req.NoReply = noReply + req.MutiCoroutine = mutiCoroutine + + if noReply == false { + req.requestHandle = func(Returns interface{},Err error){ + pCall.Err = Err + pCall.Reply = Returns + pCall.rpcHandler.(*RpcHandler).callResponeCallBack<-pCall + } + } + + if mutiCoroutine == true { + go rpcHandler.HandlerRpcRequest(&req) + }else{ + rpcHandler.PushRequest(&req) + } + return nil } - -func (server *Server) getRequest() *Request { - server.reqLock.Lock() - req := server.freeReq - if req == nil { - req = new(Request) - } else { - server.freeReq = req.next - *req = Request{} - } - server.reqLock.Unlock() - return req -} - -func (server *Server) freeRequest(req *Request) { - server.reqLock.Lock() - req.next = server.freeReq - server.freeReq = req - server.reqLock.Unlock() -} - -func (server *Server) getResponse() *Response { - server.respLock.Lock() - resp := server.freeResp - if resp == nil { - resp = new(Response) - } else { - server.freeResp = resp.next - *resp = Response{} - } - server.respLock.Unlock() - return resp -} - -func (server *Server) freeResponse(resp *Response) { - server.respLock.Lock() - resp.next = server.freeResp - server.freeResp = resp - server.respLock.Unlock() -} - -func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *methodType, req *Request, argv, replyv reflect.Value, keepReading bool, queueMode bool, err error) { - service, mtype, req, keepReading, queueMode, err = server.readRequestHeader(codec) - if err != nil { - if !keepReading { - return - } // discard body - - codec.ReadRequestBody(nil) - return - } - - // Decode the argument value. - argIsValue := false // if true, need to indirect before calling. - if mtype.ArgType.Kind() == reflect.Ptr { - argv = reflect.New(mtype.ArgType.Elem()) - } else { - argv = reflect.New(mtype.ArgType) - argIsValue = true - } - // argv guaranteed to be a pointer now. - if err = codec.ReadRequestBody(argv.Interface()); err != nil { - return - } - if argIsValue { - argv = argv.Elem() - } - - replyv = reflect.New(mtype.ReplyType.Elem()) - - switch mtype.ReplyType.Elem().Kind() { - case reflect.Map: - replyv.Elem().Set(reflect.MakeMap(mtype.ReplyType.Elem())) - case reflect.Slice: - replyv.Elem().Set(reflect.MakeSlice(mtype.ReplyType.Elem(), 0, 0)) - } - return -} - -func (server *Server) readRequestHeader(codec ServerCodec) (svc *service, mtype *methodType, req *Request, keepReading bool, queueMode bool, err error) { - // Grab the request header. - req = server.getRequest() - err = codec.ReadRequestHeader(req) - if err != nil { - req = nil - if err == io.EOF || err == io.ErrUnexpectedEOF { - return - } - err = errors.New("rpc: server cannot decode request: " + err.Error()) - return - } - - // We read the header successfully. If we see an error now, - // we can still recover and move on to the next request. - keepReading = true - - dot := strings.LastIndex(req.ServiceMethod, ".") - if dot < 0 { - err = errors.New("rpc: service/method request ill-formed: " + req.ServiceMethod) - return - } - serviceName := req.ServiceMethod[:dot] - methodName := req.ServiceMethod[dot+1:] - - // Look up the request. - svci, ok := server.serviceMap.Load(serviceName) - if !ok { - err = errors.New("rpc: can't find service " + req.ServiceMethod) - return - } - svc = svci.(*service) - mtype = svc.method[methodName] - if mtype == nil { - err = errors.New("rpc: can't find method " + req.ServiceMethod) - } - queueMode = req.QueueMode - return -} - -// Accept accepts connections on the listener and serves requests -// for each incoming connection. Accept blocks until the listener -// returns a non-nil error. The caller typically invokes Accept in a -// go statement. -func (server *Server) Accept(lis net.Listener) { - for { - conn, err := lis.Accept() - if err != nil { - log.Print("rpc.Serve: accept:", err.Error()) - return - } - go server.ServeConn(conn) - } -} - -// Register publishes the receiver's methods in the DefaultServer. -func Register(rcvr interface{}) error { return DefaultServer.Register(rcvr) } - -// RegisterName is like Register but uses the provided name for the type -// instead of the receiver's concrete type. -func RegisterName(name string, prefix string, rcvr interface{}) error { - return DefaultServer.RegisterName(name, prefix, rcvr) -} - -// A ServerCodec implements reading of RPC requests and writing of -// RPC responses for the server side of an RPC session. -// The server calls ReadRequestHeader and ReadRequestBody in pairs -// to read requests from the connection, and it calls WriteResponse to -// write a response back. The server calls Close when finished with the -// connection. ReadRequestBody may be called with a nil -// argument to force the body of the request to be read and discarded. -// See NewClient's comment for information about concurrent access. -type ServerCodec interface { - ReadRequestHeader(*Request) error - ReadRequestBody(interface{}) error - WriteResponse(*Response, interface{}) error - - // Close can be called multiple times and must be idempotent. - Close() error -} - -// ServeConn runs the DefaultServer on a single connection. -// ServeConn blocks, serving the connection until the client hangs up. -// The caller typically invokes ServeConn in a go statement. -// ServeConn uses the gob wire format (see package gob) on the -// connection. To use an alternate codec, use ServeCodec. -// See NewClient's comment for information about concurrent access. -func ServeConn(conn io.ReadWriteCloser) { - DefaultServer.ServeConn(conn) -} - -// ServeCodec is like ServeConn but uses the specified codec to -// decode requests and encode responses. -func ServeCodec(codec ServerCodec) { - DefaultServer.ServeCodec(codec) -} - -// ServeRequest is like ServeCodec but synchronously serves a single request. -// It does not close the codec upon completion. -func ServeRequest(codec ServerCodec) error { - return DefaultServer.ServeRequest(codec) -} - -// Accept accepts connections on the listener and serves requests -// to DefaultServer for each incoming connection. -// Accept blocks; the caller typically invokes it in a go statement. -func Accept(lis net.Listener) { DefaultServer.Accept(lis) } - -// Can connect to RPC service using HTTP CONNECT to rpcPath. -var connected = "200 Connected to Go RPC" - -// ServeHTTP implements an http.Handler that answers RPC requests. -func (server *Server) ServeHTTP(w http.ResponseWriter, req *http.Request) { - if req.Method != "CONNECT" { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.WriteHeader(http.StatusMethodNotAllowed) - io.WriteString(w, "405 must CONNECT\n") - return - } - conn, _, err := w.(http.Hijacker).Hijack() - if err != nil { - log.Print("rpc hijacking ", req.RemoteAddr, ": ", err.Error()) - return - } - io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n") - server.ServeConn(conn) -} - -// HandleHTTP registers an HTTP handler for RPC messages on rpcPath, -// and a debugging handler on debugPath. -// It is still necessary to invoke http.Serve(), typically in a go statement. -func (server *Server) HandleHTTP(rpcPath, debugPath string) { - http.Handle(rpcPath, server) - http.Handle(debugPath, debugHTTP{server}) -} - -// HandleHTTP registers an HTTP handler for RPC messages to DefaultServer -// on DefaultRPCPath and a debugging handler on DefaultDebugPath. -// It is still necessary to invoke http.Serve(), typically in a go statement. -func HandleHTTP() { - DefaultServer.HandleHTTP(DefaultRPCPath, DefaultDebugPath) -} diff --git a/service/DeadForMonitor.go b/service/DeadForMonitor.go deleted file mode 100644 index 4e0a0eb..0000000 --- a/service/DeadForMonitor.go +++ /dev/null @@ -1,78 +0,0 @@ -package service - -import ( - "fmt" - "github.com/duanhf2012/origin/util" - "runtime/pprof" - "time" -) - -type ModuleMontior struct { - mapModule *util.MapEx -} - -type ModuleInfo struct { - enterStartTm int64 - mNameInfo string -} - -var moduleMontior ModuleMontior - - - -func MonitorEnter(uuid string,strMonitorInfo string){ - if moduleMontior.mapModule == nil { - return - } - moduleMontior.mapModule.Set(uuid, &ModuleInfo{enterStartTm:time.Now().Unix(),mNameInfo:strMonitorInfo}) -} - -func MonitorLeave(uuid string){ - if moduleMontior.mapModule == nil { - return - } - - moduleMontior.mapModule.Del(uuid) -} - - - -func ReportDeadFor(){ - if moduleMontior.mapModule == nil { - return - } - moduleMontior.mapModule.RLockRange(func(key interface{}, value interface{}) { - if value != nil { - pModuleInfo := value.(*ModuleInfo) - //超过5分钟认为dead for - if time.Now().Unix() - pModuleInfo.enterStartTm > 300 { - GetLogger().Printf(LEVER_FATAL, "module is %s, Dead cycle\n", pModuleInfo.mNameInfo) - } - } - }) -} - -func EnableDeadForMonitor(checkInterval time.Duration){ - moduleMontior.mapModule = util.NewMapEx() - var tmInval util.Timer - tmInval.SetupTimer(int32(checkInterval.Milliseconds())) - go func(){ - for { - time.Sleep(time.Second*5) - if tmInval.CheckTimeOut(){ - ReportDeadFor() - ReportPprof() - } - } - }() -} - - -func ReportPprof(){ - strReport := "" - for _, p := range pprof.Profiles() { - strReport += fmt.Sprintf("Name %s,count %d\n",p.Name(),p.Count()) - } - - GetLogger().Printf(LEVER_INFO, "PProf %s\n", strReport) -} \ No newline at end of file diff --git a/service/Logger.go b/service/Logger.go deleted file mode 100644 index 76bec99..0000000 --- a/service/Logger.go +++ /dev/null @@ -1,37 +0,0 @@ -package service - -import ( - "fmt" -) - -const ( - LEVER_UNKNOW = 0 - LEVER_DEBUG = 1 - LEVER_INFO = 2 - LEVER_WARN = 3 - LEVER_ERROR = 4 - LEVER_FATAL = 5 - LEVEL_MAX = 6 -) - -var defaultLogger = &LoggerFmt{} - -type ILogger interface { - Printf(level uint, format string, v ...interface{}) - Print(level uint, v ...interface{}) - SetLogLevel(level uint) -} - -type LoggerFmt struct { -} - -func (slf *LoggerFmt) Printf(level uint, format string, v ...interface{}) { - fmt.Printf(format, v...) - fmt.Println("") -} -func (slf *LoggerFmt) Print(level uint, v ...interface{}) { - fmt.Println(v...) -} -func (slf *LoggerFmt) SetLogLevel(level uint) { - //do nothing -} diff --git a/service/Module.go b/service/Module.go index fc5e458..c2b6466 100644 --- a/service/Module.go +++ b/service/Module.go @@ -2,361 +2,191 @@ package service import ( "fmt" - "github.com/duanhf2012/origin/util" - "github.com/duanhf2012/origin/util/uuid" - "runtime/debug" - "sync" - "sync/atomic" + "github.com/duanhf2012/originnet/event" + "github.com/duanhf2012/originnet/util/timer" + "time" ) -const ( - //ModuleNone ... - INIT_AUTO_INCREMENT = 0 -) +const InitModuleId = 1e18 + type IModule interface { - OnInit() error //Module初始化时调用 - OnRun() bool //Module运行时调用 - OnEndRun() - SetModuleId(moduleId uint32) //手动设置ModuleId - GetModuleId() uint32 //获取ModuleId - GetModuleById(moduleId uint32) IModule //通过ModuleId获取Module - AddModule(module IModule) uint32 //添加Module - ReleaseModule(moduleId uint32) bool //释放Module - - SetSelf(module IModule) //设置保存自己interface - GetSelf() IModule //获取自己interface - SetOwner(module IModule) //设置父Module - GetOwner() IModule //获取父Module - SetOwnerService(iservice IService) //设置拥有者服务 - GetOwnerService() IService //获取拥有者服务 - GetRoot() IModule //获取Root根Module - - RunModule(module IModule) //手动运行Module - InitModule(exit chan bool, pwaitGroup *sync.WaitGroup) error //手动初始化Module - getBaseModule() *BaseModule //获取BaseModule指针 - IsInit() bool - SetUnOnRun() - getUnOnRun() bool + SetModuleId(moduleId int64) bool + GetModuleId() int64 + AddModule(module IModule) (int64,error) + GetModule(moduleId int64) IModule + GetAncestor()IModule + ReleaseModule(moduleId int64) + NewModuleId() int64 + GetParent()IModule + OnInit() error + OnRelease() + getBaseModule() IModule + GetService() IService + GetEventChan() chan *event.Event } -type BaseModule struct { - moduleId uint32 - ownerService IService - mapModule map[uint32]IModule - ownerModule IModule - selfModule IModule - CurrMaxModuleId uint32 - corouterstatus int32 //0表示运行状态 //1释放消亡状态 +//1.管理各模块树层关系 +//2.提供定时器常用工具 +type Module struct { + moduleId int64 + parent IModule //父亲 + self IModule //父亲 + child map[int64]IModule //孩子们 + mapActiveTimer map[*timer.Timer]interface{} + mapActiveCron map[*timer.Cron]interface{} - moduleLocker sync.RWMutex - ExitChan chan bool - WaitGroup *sync.WaitGroup - bInit bool + dispatcher *timer.Dispatcher //timer - recoverCount int8 - bUnOnRun bool + //根结点 + ancestor IModule //始祖 + seedModuleId int64 //模块id种子 + descendants map[int64]IModule//始祖的后裔们 + + //事件管道 + event.EventProcessor + //eventChan chan *SEvent } -func (slf *BaseModule) GetRoot() IModule { - currentOwner := slf.GetSelf() - for { - owner := currentOwner.GetOwner() - if owner == currentOwner { - return owner - } - currentOwner = owner - } -} -func (slf *BaseModule) SetModuleId(moduleId uint32) { - slf.moduleId = moduleId -} - -func (slf *BaseModule) GetModuleId() uint32 { - return slf.moduleId -} - -func (slf *BaseModule) GetModuleById(moduleId uint32) IModule { - slf.moduleLocker.RLock() - ret, ok := slf.mapModule[moduleId] - slf.moduleLocker.RUnlock() - if ok == false { - return nil - } - - return ret -} - -func (slf *BaseModule) GetModuleCount() int { - slf.moduleLocker.RLock() - moduleCount := len(slf.mapModule) - slf.moduleLocker.RUnlock() - return moduleCount -} - -func (slf *BaseModule) genModuleId() uint32 { - slf.CurrMaxModuleId++ - - return slf.CurrMaxModuleId -} - -func (slf *BaseModule) deleteModule(baseModule *BaseModule) bool { - for _, subModule := range baseModule.mapModule { - baseModule.deleteModule(subModule.getBaseModule()) - } - - atomic.AddInt32(&baseModule.corouterstatus, 1) - //fmt.Printf("Delete %T->%T\n", slf.GetSelf(), baseModule.GetSelf()) - baseModule.ownerService = nil - baseModule.mapModule = nil - baseModule.ownerModule = nil - baseModule.selfModule = nil - - delete(slf.mapModule, baseModule.GetModuleId()) - baseModule.moduleLocker.Unlock() - - return true -} - -func (slf *BaseModule) LockTree(rootModule *BaseModule) { - rootModule.moduleLocker.Lock() - //fmt.Printf("Lock %T\n", rootModule.GetSelf()) - - for _, pModule := range rootModule.mapModule { - slf.LockTree(pModule.getBaseModule()) - //pModule.getBaseModule().moduleLocker.Lock() - } -} - -func (slf *BaseModule) UnLockTree(rootModule *BaseModule) { - for _, pModule := range rootModule.mapModule { - pModule.getBaseModule().moduleLocker.Unlock() - } - rootModule.moduleLocker.Unlock() -} - -func (slf *BaseModule) ReleaseModule(moduleId uint32) bool { - slf.moduleLocker.Lock() - - module, ok := slf.mapModule[moduleId] - if ok == false { - slf.moduleLocker.Unlock() - GetLogger().Printf(LEVER_FATAL, "RemoveModule fail %d...", moduleId) +func (slf *Module) SetModuleId(moduleId int64) bool{ + if moduleId > 0 { return false } - //锁住被结点树 - slf.LockTree(module.getBaseModule()) - slf.deleteModule(module.getBaseModule()) - - delete(slf.mapModule, moduleId) - - //fmt.Printf("++Release %T -- %+v\n", slf.GetSelf(), slf.mapModule) - slf.moduleLocker.Unlock() + slf.moduleId = moduleId return true } -func (slf *BaseModule) IsRoot() bool { - return slf.GetOwner() == slf.GetSelf() +func (slf *Module) GetModuleId() int64{ + return slf.moduleId } -func (slf *BaseModule) GetSelf() IModule { - if slf.selfModule == nil { - return slf - } - - return slf.selfModule +func (slf *Module) OnInit() error{ + return nil } -func (slf *BaseModule) SetUnOnRun() { - slf.bUnOnRun = true -} - -func (slf *BaseModule) getUnOnRun() bool { - return slf.bUnOnRun -} - -func (slf *BaseModule) AddModule(module IModule) uint32 { - //消亡状态不允许加入模块 - if atomic.LoadInt32(&slf.corouterstatus) != 0 { - GetLogger().Printf(LEVER_ERROR, "%T Cannot AddModule %T", slf.GetSelf(), module.GetSelf()) - return 0 +func (slf *Module) AddModule(module IModule) (int64,error){ + pAddModule := module.getBaseModule().(*Module) + if pAddModule.GetModuleId()==0 { + pAddModule.moduleId = slf.NewModuleId() } - pModule := slf.GetModuleById(module.GetModuleId()) - if pModule != nil { - GetLogger().Printf(LEVER_ERROR, "%T Cannot AddModule %T,moduleid %d is repeat!", slf.GetSelf(), module.GetSelf(), module.GetModuleId()) - return 0 + if slf.child == nil { + slf.child = map[int64]IModule{} } - - //如果没有设置,自动生成ModuleId - slf.moduleLocker.Lock() - var genid uint32 - if module.GetModuleId() == 0 { - genid = slf.genModuleId() - module.SetModuleId(genid) - } - - module.getBaseModule().selfModule = module - if slf.GetOwner() != nil { - if slf.IsRoot() { - //root owner为自己 - module.SetOwner(slf.GetOwner()) - } else { - module.SetOwner(slf.GetSelf()) - } - } - - //设置模块退出信号捕获 - module.InitModule(slf.ExitChan, slf.WaitGroup) - - //存入父模块中 - if slf.mapModule == nil { - slf.mapModule = make(map[uint32]IModule) - } - _, ok := slf.mapModule[module.GetModuleId()] + _,ok := slf.child[module.GetModuleId()] if ok == true { - slf.moduleLocker.Unlock() - GetLogger().Printf(LEVER_ERROR, "check mapModule %#v id is %d ,%d is fail...", module, module.GetModuleId(), genid) - return 0 + return 0,fmt.Errorf("Exists module id %d",module.GetModuleId()) } - slf.mapModule[module.GetModuleId()] = module + pAddModule.self = module + pAddModule.parent = slf.self + pAddModule.dispatcher = slf.GetAncestor().getBaseModule().(*Module).dispatcher + pAddModule.ancestor = slf.ancestor - slf.moduleLocker.Unlock() - - //运行模块 - GetLogger().Printf(LEVER_INFO, "Start Init module %T.", module) err := module.OnInit() if err != nil { - delete(slf.mapModule, module.GetModuleId()) - GetLogger().Printf(LEVER_ERROR, "End Init module %T id is %d is fail,reason:%v...", module, module.GetModuleId(), err) - return 0 - } - initErr := module.getBaseModule().OnInit() - if initErr != nil { - delete(slf.mapModule, module.GetModuleId()) - GetLogger().Printf(LEVER_ERROR, "OnInit module %T id is %d is fail,reason:%v...", module, module.GetModuleId(), initErr) - return 0 + return 0,err } - GetLogger().Printf(LEVER_INFO, "End Init module %T.", module) - if module.getUnOnRun() == false { - go module.RunModule(module) + slf.child[module.GetModuleId()] = module + slf.ancestor.getBaseModule().(*Module).descendants[module.GetModuleId()] = module + + return module.GetModuleId(),nil +} + +func (slf *Module) ReleaseModule(moduleId int64){ + //pBaseModule := slf.GetModule(moduleId).getBaseModule().(*Module) + pModule := slf.GetModule(moduleId).getBaseModule().(*Module) + + //释放子孙 + for id,_ := range pModule.child { + slf.ReleaseModule(id) + } + pModule.self.OnRelease() + for pTimer,_ := range pModule.mapActiveTimer { + pTimer.Stop() } - return module.GetModuleId() -} - -func (slf *BaseModule) OnInit() error { - slf.bInit = true - return nil -} - -func (slf *BaseModule) OnRun() bool { - return false -} - -func (slf *BaseModule) OnEndRun() { -} - -func (slf *BaseModule) SetOwner(ownerModule IModule) { - slf.ownerModule = ownerModule -} - -func (slf *BaseModule) SetSelf(module IModule) { - slf.selfModule = module -} - -func (slf *BaseModule) GetOwner() IModule { - - if slf.ownerModule == nil { - return slf + for pCron,_ := range pModule.mapActiveCron { + pCron.Stop() } - return slf.ownerModule + + delete(slf.child,moduleId) + delete (slf.ancestor.getBaseModule().(*Module).descendants,moduleId) + + //清理被删除的Module + pModule.self = nil + pModule.parent = nil + pModule.child = nil + pModule.mapActiveTimer = nil + pModule.mapActiveCron = nil + pModule.dispatcher = nil + pModule.ancestor = nil + pModule.descendants = nil } -func (slf *BaseModule) GetOwnerService() IService { - return slf.ownerService +func (slf *Module) NewModuleId() int64{ + slf.ancestor.getBaseModule().(*Module).seedModuleId+=1 + return slf.ancestor.getBaseModule().(*Module).seedModuleId } -func (slf *BaseModule) SetOwnerService(iservice IService) { - slf.ownerService = iservice +func (slf *Module) GetAncestor()IModule{ + return slf.ancestor } -func (slf *BaseModule) InitModule(exit chan bool, pwaitGroup *sync.WaitGroup) error { - slf.CurrMaxModuleId = INIT_AUTO_INCREMENT - slf.WaitGroup = pwaitGroup - slf.ExitChan = exit - return nil +func (slf *Module) GetModule(moduleId int64) IModule{ + iModule,ok := slf.GetAncestor().getBaseModule().(*Module).descendants[moduleId] + if ok == false{ + return nil + } + return iModule } -func (slf *BaseModule) getBaseModule() *BaseModule { +func (slf *Module) getBaseModule() IModule{ return slf } -func (slf *BaseModule) IsInit() bool { - return slf.bInit + +func (slf *Module) GetParent()IModule{ + return slf.parent } -func (slf *BaseModule) RunModule(module IModule) { - GetLogger().Printf(LEVER_INFO, "Start Run module %T ...", module) - - defer func() { - if r := recover(); r != nil { - var coreInfo string - coreInfo = string(debug.Stack()) - - coreInfo += "\n" + fmt.Sprintf("Core module is %T, try count %d. core information is %v\n", module, slf.recoverCount, r) - GetLogger().Printf(LEVER_FATAL, coreInfo) - slf.recoverCount += 1 - - //重试3次 - if slf.recoverCount < 10 { - go slf.RunModule(slf.GetSelf()) - } else { - GetLogger().Printf(LEVER_FATAL, "Routine %T.OnRun has exited!", module) - } - } - }() - - //运行所有子模块 - timer := util.Timer{} - timer.SetupTimer(1000) - slf.WaitGroup.Add(1) - defer slf.WaitGroup.Done() - - uuidkey := uuid.Rand().HexEx() - moduleTypeName := fmt.Sprintf("%T",module) - for { - if atomic.LoadInt32(&slf.corouterstatus) != 0 { - module.OnEndRun() - GetLogger().Printf(LEVER_INFO, "OnEndRun module %T ...", module) - break - } - - //每500ms检查退出 - if timer.CheckTimeOut() { - select { - case <-slf.ExitChan: - module.OnEndRun() - GetLogger().Printf(LEVER_INFO, "OnEndRun module %T...", module) - return - default: - } - } - - MonitorEnter(uuidkey,moduleTypeName) - if module.OnRun() == false { - module.OnEndRun() - MonitorLeave(uuidkey) - GetLogger().Printf(LEVER_INFO, "OnEndRun module %T...", module) - return - } - - MonitorLeave(uuidkey) +func (slf *Module) AfterFunc(d time.Duration, cb func()) *timer.Timer { + if slf.mapActiveTimer == nil { + slf.mapActiveTimer =map[*timer.Timer]interface{}{} } + + tm := slf.dispatcher.AfterFuncEx(d,func(t *timer.Timer){ + cb() + delete(slf.mapActiveTimer,t) + }) + + slf.mapActiveTimer[tm] = nil + return tm } + +func (slf *Module) CronFunc(cronExpr *timer.CronExpr, cb func()) *timer.Cron { + if slf.mapActiveCron == nil { + slf.mapActiveCron =map[*timer.Cron]interface{}{} + } + + cron := slf.dispatcher.CronFuncEx(cronExpr, func(cron *timer.Cron) { + cb() + delete(slf.mapActiveCron,cron) + }) + + slf.mapActiveCron[cron] = nil + return cron +} + +func (slf *Module) OnRelease(){ +} + +func (slf *Module) GetService() IService { + return slf.GetAncestor().(IService) +} + diff --git a/service/Service.go b/service/Service.go index 30a3adb..a9d6614 100644 --- a/service/Service.go +++ b/service/Service.go @@ -1,85 +1,126 @@ package service import ( - "fmt" - + "github.com/duanhf2012/originnet/rpc" + "github.com/duanhf2012/originnet/util/timer" "reflect" - "strings" + "sync" + "sync/atomic" ) -type MethodInfo struct { - Fun reflect.Value - ParamList []reflect.Value - types reflect.Type -} + +var closeSig chan bool +var timerDispatcherLen = 10 type IService interface { - Init(Iservice IService) error + Init(iservice IService,getClientFun rpc.FuncRpcClient,getServerFun rpc.FuncRpcServer,serviceCfg interface{}) + GetName() string + OnInit() error - OnRun() bool - OnFetchService(iservice IService) error - OnSetupService(iservice IService) //其他服务被安装 - OnRemoveService(iservice IService) //其他服务被安装 - - GetServiceName() string - SetServiceName(serviceName string) bool - GetServiceId() int - - GetStatus() int - IsInit() bool + OnRelease() + Wait() + Start() + GetRpcHandler() rpc.IRpcHandler + GetServiceCfg()interface{} } -type BaseService struct { - BaseModule - serviceid int - servicename string - Status int + +type Service struct { + Module + rpc.RpcHandler //rpc + name string //service name + closeSig chan bool + wg sync.WaitGroup + this IService + serviceCfg interface{} + gorouterNum int32 + startStatus bool } -func (slf *BaseService) GetServiceId() int { - return slf.serviceid +func (slf *Service) Init(iservice IService,getClientFun rpc.FuncRpcClient,getServerFun rpc.FuncRpcServer,serviceCfg interface{}) { + slf.name = reflect.Indirect(reflect.ValueOf(iservice)).Type().Name() + slf.dispatcher =timer.NewDispatcher(timerDispatcherLen) + slf.this = iservice + slf.InitRpcHandler(iservice.(rpc.IRpcHandler),getClientFun,getServerFun) + + //初始化祖先 + slf.ancestor = iservice.(IModule) + slf.seedModuleId =InitModuleId + slf.descendants = map[int64]IModule{} + slf.serviceCfg = serviceCfg + slf.gorouterNum = 1 + slf.this.OnInit() } -func (slf *BaseService) GetServiceName() string { - return slf.servicename -} +func (slf *Service) SetGoRouterNum(gorouterNum int32) bool { + //已经开始状态不允许修改协程数量 + if slf.startStatus == true { + return false + } -func (slf *BaseService) SetServiceName(serviceName string) bool { - slf.servicename = serviceName + slf.gorouterNum = gorouterNum return true } -func (slf *BaseService) GetStatus() int { - return slf.Status +func (slf *Service) Start() { + slf.startStatus = true + for i:=int32(0);i= MAX_EXECUTE_FUN { + chanIndex := queryHas % len(slf.executeList) + if chanIndex < 0 { + chanIndex = rand.Intn(len(slf.executeList)) + } + + if len(slf.executeList[chanIndex].syncExecuteFun) >= MAX_EXECUTE_FUN { dbret := DataSetList{} ret.err <- fmt.Errorf("chan is full,sql:%s", query) ret.sres <- &dbret @@ -507,7 +568,7 @@ func (slf *DBModule) SyncQuery(query string, args ...interface{}) SyncQueryDBRes return ret } - slf.syncExecuteFun <- func() { + slf.executeList[chanIndex].syncExecuteFun <- func() { rsp, err := slf.QueryEx(query, args...) ret.err <- err ret.sres <- rsp @@ -516,16 +577,35 @@ func (slf *DBModule) SyncQuery(query string, args ...interface{}) SyncQueryDBRes return ret } +func (slf *DBModule) AsyncQuery(call SyncDBResultExCallBack, queryHas int, query string, args ...interface{}) error { + chanIndex := queryHas % len(slf.executeList) + if chanIndex < 0 { + chanIndex = rand.Intn(len(slf.executeList)) + } + + if len(slf.executeList[chanIndex].syncExecuteFun) >= MAX_EXECUTE_FUN { + return fmt.Errorf("chan is full,sql:%s", query) + } + + slf.executeList[chanIndex].syncExecuteFun <- func() { + rsp, err := slf.QueryEx(query, args...) + call(rsp, err) + return + } + + return nil +} + // Exec ... func (slf *DBModule) Exec(query string, args ...interface{}) (*DBResultEx, error) { ret := &DBResultEx{} if slf.db == nil { - service.GetLogger().Printf(service.LEVER_ERROR, "cannot connect database:%s", query) + log.Error("cannot connect database:%s", query) return ret, fmt.Errorf("cannot connect database!") } if slf.CheckArgs(args) != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "CheckArgs is error :%s", query) + log.Error("CheckArgs is error :%s", query) //return ret, fmt.Errorf("cannot connect database!") return ret, fmt.Errorf("CheckArgs is error!") } @@ -534,10 +614,10 @@ func (slf *DBModule) Exec(query string, args ...interface{}) (*DBResultEx, error res, err := slf.db.Exec(query, args...) TimeFuncPass := time.Since(TimeFuncStart) if slf.IsPrintTimeLog(TimeFuncPass) { - service.GetLogger().Printf(service.LEVER_INFO, "DBModule QueryEx Time %s , Query :%s , args :%+v", TimeFuncPass, query, args) + log.Error("DBModule QueryEx Time %s , Query :%s , args :%+v", TimeFuncPass, query, args) } if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Exec:%s(%v)", query, err) + log.Error("Exec:%s(%v)", query, err) return nil, err } @@ -548,18 +628,23 @@ func (slf *DBModule) Exec(query string, args ...interface{}) (*DBResultEx, error } // SyncExec ... -func (slf *DBModule) SyncExec(query string, args ...interface{}) *SyncExecuteDBResult { +func (slf *DBModule) SyncExec(queryHas int, query string, args ...interface{}) *SyncExecuteDBResult { ret := &SyncExecuteDBResult{ sres: make(chan *DBResultEx, 1), err: make(chan error, 1), } - if len(slf.syncExecuteFun) >= MAX_EXECUTE_FUN { + chanIndex := queryHas % len(slf.executeList) + if chanIndex < 0 { + chanIndex = rand.Intn(len(slf.executeList)) + } + + if len(slf.executeList[chanIndex].syncExecuteFun) >= MAX_EXECUTE_FUN { ret.err <- fmt.Errorf("chan is full,sql:%s", query) return ret } - slf.syncExecuteFun <- func() { + slf.executeList[chanIndex].syncExecuteFun <- func() { rsp, err := slf.Exec(query, args...) if err != nil { ret.err <- err @@ -573,19 +658,41 @@ func (slf *DBModule) SyncExec(query string, args ...interface{}) *SyncExecuteDBR return ret } -func (slf *DBModule) RunExecuteDBCoroutine() { - slf.WaitGroup.Add(1) - defer slf.WaitGroup.Done() +func (slf *DBModule) AsyncExec(call SyncDBResultExCallBack, queryHas int, query string, args ...interface{}) error { + chanIndex := queryHas % len(slf.executeList) + if chanIndex < 0 { + chanIndex = rand.Intn(len(slf.executeList)) + } + + if len(slf.executeList[chanIndex].syncExecuteFun) >= MAX_EXECUTE_FUN { + return fmt.Errorf("chan is full,sql:%s", query) + } + + slf.executeList[chanIndex].syncExecuteFun <- func() { + rsp, err := slf.Exec(query, args...) + + data := DataSetList{tag:"json", blur:true, dataSetList:[]DBResultEx{}} + data.dataSetList = append(data.dataSetList, *rsp) + call(&data, err) + + return + } + + return nil +} + +func (slf *DBModule) RunExecuteDBCoroutine(has int) { + slf.waitGroup.Add(1) + defer slf.waitGroup.Done() for { select { - case <-slf.ExitChan: - service.GetLogger().Printf(LEVER_WARN, "stopping module %s...", fmt.Sprintf("%T", slf)) + case <-slf.executeList[has].syncExecuteExit: + log.Error("stopping module %s...", fmt.Sprintf("%T", slf)) return - case fun := <-slf.syncExecuteFun: + case fun := <-slf.executeList[has].syncExecuteFun: fun() } } - } func (slf *DataSetList) UnMarshal(args ...interface{}) error { @@ -740,7 +847,7 @@ func (slf *DBModule) Begin() (*Tx, error) { var txDBMoudule Tx txdb, err := slf.db.Begin() if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Begin error:%s", err.Error()) + log.Error("Begin error:%s", err.Error()) return &txDBMoudule, err } txDBMoudule.tx = txdb @@ -805,21 +912,21 @@ func (slf *Tx) CheckArgs(args ...interface{}) error { func (slf *Tx) Query(query string, args ...interface{}) DBResult { if slf.CheckArgs(args) != nil { ret := DBResult{} - service.GetLogger().Printf(service.LEVER_ERROR, "CheckArgs is error :%s", query) + log.Error("CheckArgs is error :%s", query) ret.Err = fmt.Errorf("CheckArgs is error!") return ret } if slf.tx == nil { ret := DBResult{} - service.GetLogger().Printf(service.LEVER_ERROR, "cannot connect database:%s", query) + log.Error("cannot connect database:%s", query) ret.Err = fmt.Errorf("cannot connect database!") return ret } rows, err := slf.tx.Query(query, args...) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Tx Query:%s(%v)", query, err) + log.Error("Tx Query:%s(%v)", query, err) } return DBResult{ @@ -845,12 +952,12 @@ func (slf *Tx) QueryEx(query string, args ...interface{}) (*DataSetList, error) datasetList.blur = true if slf.CheckArgs(args) != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "CheckArgs is error :%s", query) + log.Error("CheckArgs is error :%s", query) return &datasetList, fmt.Errorf("CheckArgs is error!") } if slf.tx == nil { - service.GetLogger().Printf(service.LEVER_ERROR, "cannot connect database:%s", query) + log.Error("cannot connect database:%s", query) return &datasetList, fmt.Errorf("cannot connect database!") } @@ -859,10 +966,10 @@ func (slf *Tx) QueryEx(query string, args ...interface{}) (*DataSetList, error) TimeFuncPass := time.Since(TimeFuncStart) if slf.IsPrintTimeLog(TimeFuncPass) { - service.GetLogger().Printf(service.LEVER_INFO, "Tx QueryEx Time %s , Query :%s , args :%+v", TimeFuncPass, query, args) + log.Error("Tx QueryEx Time %s , Query :%s , args :%+v", TimeFuncPass, query, args) } if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Tx Query:%s(%v)", query, err) + log.Error("Tx Query:%s(%v)", query, err) if rows != nil { rows.Close() } @@ -903,7 +1010,7 @@ func (slf *Tx) QueryEx(query string, args ...interface{}) (*DataSetList, error) if hasRet == false { if rows.Err() != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Tx Query:%s(%+v)", query, rows) + log.Error("Tx Query:%s(%+v)", query, rows) } break } @@ -916,12 +1023,12 @@ func (slf *Tx) QueryEx(query string, args ...interface{}) (*DataSetList, error) func (slf *Tx) Exec(query string, args ...interface{}) (*DBResultEx, error) { ret := &DBResultEx{} if slf.tx == nil { - service.GetLogger().Printf(service.LEVER_ERROR, "cannot connect database:%s", query) + log.Error("cannot connect database:%s", query) return ret, fmt.Errorf("cannot connect database!") } if slf.CheckArgs(args) != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "CheckArgs is error :%s", query) + log.Error("CheckArgs is error :%s", query) //return ret, fmt.Errorf("cannot connect database!") return ret, fmt.Errorf("CheckArgs is error!") } @@ -930,10 +1037,10 @@ func (slf *Tx) Exec(query string, args ...interface{}) (*DBResultEx, error) { res, err := slf.tx.Exec(query, args...) TimeFuncPass := time.Since(TimeFuncStart) if slf.IsPrintTimeLog(TimeFuncPass) { - service.GetLogger().Printf(service.LEVER_INFO, "Tx QueryEx Time %s , Query :%s , args :%+v", TimeFuncPass, query, args) + log.Error("Tx QueryEx Time %s , Query :%s , args :%+v", TimeFuncPass, query, args) } if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Tx Exec:%s(%v)", query, err) + log.Error("Tx Exec:%s(%v)", query, err) return nil, err } diff --git a/sysmodule/DBModule_test.go b/sysmodule/DBModule_test.go deleted file mode 100644 index 1eba7f1..0000000 --- a/sysmodule/DBModule_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package sysmodule_test - -import ( - "fmt" - "sync" - "testing" - - "github.com/duanhf2012/origin/sysmodule" - _ "github.com/go-sql-driver/mysql" -) - -func TestDBModule(t *testing.T) { - db := sysmodule.DBModule{} - db.ExitChan = make(chan bool) - db.WaitGroup = new(sync.WaitGroup) - - // db.Init(100, "192.168.0.5:3306", "root", "Root!!2018", "QuantFundsDB") - db.Init(100, "127.0.0.1:3306", "root", "zgh50221", "rebort_message") - db.OnInit() - tx, err := db.GetTx() - if err != nil { - fmt.Println("err 1", err) - return - } - res, err := tx.QueryEx("select id as Id, info_type as InfoType, info_type_Name as InfoTypeName from tbl_info_type where id >= 1") - if err != nil { - fmt.Println("err 2", err) - tx.Rollback() - return - } - out := []struct { - Id int64 - InfoType string - InfoTypeName string - }{} - err = res.UnMarshal(&out) - if err != nil { - fmt.Println("err 3", err) - tx.Rollback() - return - } - fmt.Println(out) - _, err = tx.Exec("insert into tbl_info_type(info_type, info_type_name) VALUES (?, ?)", "4", "weibo") - if err != nil { - fmt.Println("err 4", err) - tx.Rollback() - return - } - _, err = tx.Exec("update tbl_info_type set info_types = ? Where id = ?", "5", 0) - if err != nil { - fmt.Println("err 4", err) - tx.Rollback() - return - } - - tx.Commit() - // res, err := db.QueryEx("select * from tbl_fun_heelthrow where id >= 1") - // if err != nil { - // t.Error(err) - // } - // out := []struct { - // Addtime int64 `json:"addtime"` - // Tname string `json:"tname"` - // Uuid string `json:"uuid,omitempty"` - // AAAA string `json:"xxx"` - // }{} - // err = res.UnMarshal(&out) - // if err != nil { - // t.Error(err) - // } - - // sres := db.SyncQuery("select * from tbl_fun_heelthrow where id >= 1") - // res, err = sres.Get(2000) - // if err != nil { - // t.Error(err) - // } - - // out2 := []struct { - // Addtime int64 `json:"addtime"` - // Tname string `json:"tname"` - // Uuid string `json:"uuid,omitempty"` - // AAAA string `json:"xxx"` - // }{} - - // err = res.UnMarshal(&out2) - // if err != nil { - // t.Error(err) - // } -} diff --git a/sysmodule/HttpClientPoolModule.go b/sysmodule/HttpClientPoolModule.go index f970546..97c0723 100644 --- a/sysmodule/HttpClientPoolModule.go +++ b/sysmodule/HttpClientPoolModule.go @@ -10,11 +10,11 @@ import ( "net/url" "time" - "github.com/duanhf2012/origin/service" + "github.com/duanhf2012/originnet/service" ) type HttpClientPoolModule struct { - service.BaseModule + service.Module client *http.Client } diff --git a/sysmodule/HttpClientPoolModule_test.go b/sysmodule/HttpClientPoolModule_test.go deleted file mode 100644 index c2f674a..0000000 --- a/sysmodule/HttpClientPoolModule_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package sysmodule_test - -import ( - "fmt" - "net/http" - "testing" - - "github.com/duanhf2012/origin/sysmodule" -) - -func TestHttpClientPoolModule(t *testing.T) { - c := sysmodule.HttpClientPoolModule{} - c.Init(10, "") - - rsp := c.Request(http.MethodGet, "https://www.baidu.com/", nil, nil) - fmt.Println(rsp.Err) - fmt.Println(rsp.Header) - fmt.Println(rsp.StatusCode) - fmt.Println(rsp.Status) - fmt.Println(string(rsp.Body)) - - srsp := c.SyncRequest(http.MethodGet, "https://www.baidu.com/", nil, nil) - rsp1 := srsp.Get(1) - fmt.Println(rsp1.Err) - fmt.Println(rsp1.Header) - fmt.Println(rsp1.StatusCode) - fmt.Println(rsp1.Status) - fmt.Println(string(rsp1.Body)) -} diff --git a/sysmodule/LogModule.go b/sysmodule/LogModule.go deleted file mode 100644 index ff6cc14..0000000 --- a/sysmodule/LogModule.go +++ /dev/null @@ -1,190 +0,0 @@ -package sysmodule - -import ( - "fmt" - "log" - "os" - "path/filepath" - "runtime" - "strings" - "sync" - "time" - - "github.com/duanhf2012/origin/service" -) - -const ( - maxLinesInLog = 100000 //一个日志文件最多只写这么多行 -) - -//等级从低到高 -const ( - LEVER_UNKNOW = 0 - LEVER_DEBUG = 1 - LEVER_INFO = 2 - LEVER_WARN = 3 - LEVER_ERROR = 4 - LEVER_FATAL = 5 - LEVEL_MAX = 6 -) - -var LogPrefix = [LEVEL_MAX]string{"[UNKNOW]", "[DEBUG]", "[INFO ]", "[WARN ]", "[ERROR]", "[FATAL]"} - -type ILogger interface { - Printf(level uint, format string, v ...interface{}) - Print(level uint, v ...interface{}) - SetLogLevel(level uint) -} - -type FunListenLog func(uint, string) - -type LogModule struct { - service.BaseModule - currentDay int64 - lines int64 - logfilename string - logger [LEVEL_MAX]*log.Logger - logFile *os.File - openLevel uint - locker sync.Mutex - calldepth int - listenFun FunListenLog -} - -func (slf *LogModule) GetCurrentFileName() string { - now := time.Now() - fpath := filepath.Join("logs") - os.MkdirAll(fpath, os.ModePerm) - y, m, d := now.Date() - h := now.Hour() - mm := now.Minute() - mm -= mm % 15 //15分钟内使用同一个日志文件 - dt := y*10000 + int(m)*100 + d - tm := h*100 + mm - fname := fmt.Sprintf("%s-%d-%d.log", slf.logfilename, dt, tm) - ret := filepath.Join(fpath, fname) - return ret -} - -//检查是否需要切换新的日志文件 -func (slf *LogModule) CheckAndGenFile(fileline string) (newFile bool) { - now := time.Now() - nowDate := int64(now.Day()) - - slf.locker.Lock() - - isNewDay := nowDate != slf.currentDay - slf.lines++ - if isNewDay || slf.lines > maxLinesInLog { - // if time.Now().Day() == slf.currentDay { - // slf.locker.Unlock() - // return - // } - //fmt.Println("new log file", slf.currentDay, nowDate, isNewDay, slf.lines, maxLinesInLog) - - slf.currentDay = nowDate - slf.lines = 1 - newFile = true - if slf.logFile != nil { - slf.logFile.Close() - } - - var err error - filename := slf.GetCurrentFileName() - slf.logFile, err = os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) - if err != nil { - fmt.Printf("create log file %+v error!", filename) - slf.locker.Unlock() - return false - } - - for level := 0; level < LEVEL_MAX; level++ { - slf.logger[level] = log.New(slf.logFile, LogPrefix[level], log.Lshortfile|log.LstdFlags) - } - } - - slf.locker.Unlock() - return newFile -} - -func (slf *LogModule) Init(logFilePrefixName string, openLevel uint) { - slf.currentDay = 0 - slf.logfilename = logFilePrefixName - slf.openLevel = openLevel - slf.calldepth = 3 -} - -func (slf *LogModule) SetListenLogFunc(listenFun FunListenLog) { - slf.listenFun = listenFun -} - -func (slf *LogModule) GetLoggerByLevel(level uint) *log.Logger { - if level >= LEVEL_MAX { - level = 0 - } - return slf.logger[level] -} - -func (slf *LogModule) Printf(level uint, format string, v ...interface{}) { - if level < slf.openLevel { - return - } - - _, file, line, ok := runtime.Caller(slf.calldepth - 1) - if !ok { - file = "???" - line = 0 - } - fileLine := fmt.Sprintf(" %s:%d: ", file, line) - slf.CheckAndGenFile(fileLine) - - logContents := fmt.Sprintf(format, v...) - slf.doPutLog(level, fileLine, logContents) -} - -func (slf *LogModule) Print(level uint, v ...interface{}) { - if level < slf.openLevel { - return - } - - _, file, line, ok := runtime.Caller(slf.calldepth - 1) - if !ok { - file = "???" - line = 0 - } - fileLine := fmt.Sprintf(" %s:%d: ", file, line) - slf.CheckAndGenFile(fileLine) - - logContents := fmt.Sprint(v...) - slf.doPutLog(level, fileLine, logContents) -} - -//最终写日志的接口 -func (slf *LogModule) doPutLog(level uint, fileLine, logContents string) { - if slf.openLevel == LEVER_DEBUG || slf.listenFun != nil { - strlog := fmt.Sprintf("%s %s %s", LogPrefix[level], time.Now().Format("2006-01-02 15:04:05"), logContents) - if slf.openLevel == LEVER_DEBUG { - fmt.Println(strlog) - } - - if slf.listenFun != nil { - fline := fileLine - if idx := strings.LastIndex(fileLine, "/"); idx >= 0 { - fline = fileLine[idx+1:] - } - - ft := fline + " " + strlog - slf.listenFun(level, fmt.Sprintf(ft)) - } - } - - slf.GetLoggerByLevel(level).Output(slf.calldepth+1, logContents) -} - -func (slf *LogModule) AppendCallDepth(calldepth int) { - slf.calldepth += calldepth -} - -func (slf *LogModule) SetLogLevel(level uint) { - slf.openLevel = level -} diff --git a/sysmodule/RedisModule.go b/sysmodule/RedisModule.go index cbf30c6..4d443a4 100644 --- a/sysmodule/RedisModule.go +++ b/sysmodule/RedisModule.go @@ -5,9 +5,10 @@ import ( "encoding/json" "errors" "fmt" + "github.com/duanhf2012/originnet/log" "time" - "github.com/duanhf2012/origin/service" + "github.com/duanhf2012/originnet/service" "github.com/gomodule/redigo/redis" ) @@ -39,7 +40,7 @@ func (slf *RetMapString) Get() (error, map[string]bool) { type Func func() type RedisModule struct { - service.BaseModule + service.Module redispool *redis.Pool redisTask chan Func } @@ -71,7 +72,7 @@ func (slf *RedisModule) Init(redisCfg *ConfigRedis) { } c, err := redis.Dial("tcp", redisServer, opt...) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Connect redis fail reason:%v", err) + log.Error("Connect redis fail reason:%v", err) return nil, err } @@ -84,7 +85,7 @@ func (slf *RedisModule) Init(redisCfg *ConfigRedis) { } _, err := c.Do("PING") if err != nil { - service.GetLogger().Printf(service.LEVER_WARN, "Do PING fail reason:%v", err) + log.Error("Do PING fail reason:%v", err) return err } return err @@ -107,7 +108,7 @@ func (slf *RedisModule) RunAnsyTask() { func (slf *RedisModule) GoTask(fc Func) error { if len(slf.redisTask) >= MAX_TASK_CHANNEL { - service.GetLogger().Printf(service.LEVER_ERROR, "Redis task channel recover max.") + log.Error("Redis task channel recover max.") return fmt.Errorf("Redis task channel recover max.") } @@ -118,19 +119,19 @@ func (slf *RedisModule) GoTask(fc Func) error { // GetConn ... func (slf *RedisModule) getConn() (redis.Conn, error) { if slf.redispool == nil { - service.GetLogger().Printf(service.LEVER_FATAL, "Not Init RedisModule") + log.Error("Not Init RedisModule") return nil, fmt.Errorf("Not Init RedisModule") } conn := slf.redispool.Get() if conn == nil { - service.GetLogger().Printf(service.LEVER_ERROR, "Cannot get connection") + log.Error("Cannot get connection") return nil, fmt.Errorf("Cannot get connection") } if conn.Err() != nil { err := conn.Err() if err != nil { - service.GetLogger().Printf(service.LEVER_WARN, "Get Conn have error,reason:%v", err) + log.Error("Get Conn have error,reason:%v", err) } conn.Close() return nil, err @@ -148,7 +149,7 @@ func (slf *RedisModule) TestPingRedis() error { err = slf.redispool.TestOnBorrow(conn, time.Now()) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "TestOnBorrow fail,reason:%v", err) + log.Error("TestOnBorrow fail,reason:%v", err) return err } @@ -222,7 +223,7 @@ func (slf *RedisModule) GoSetStringJSONExpire(key string, val interface{}, expir slf.GoSetStringExpire(key, string(temp), expire, retErr) return nil } else { - service.GetLogger().Printf(service.LEVER_ERROR, "GoSetStringJSONExpire fail,reason:%v", err) + log.Error("GoSetStringJSONExpire fail,reason:%v", err) retErr.resultChan <- err } return err @@ -248,14 +249,14 @@ func (slf *RedisModule) setStringByExpire(key, value, expire string) error { } if retErr != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "setStringByExpire fail,reason:%v", retErr) + log.Error("setStringByExpire fail,reason:%v", retErr) return retErr } _, ok := ret.(string) if !ok { retErr = errors.New("setStringByExpire redis data is error") - service.GetLogger().Printf(service.LEVER_ERROR, "setStringByExpire redis data is error") + log.Error("setStringByExpire redis data is error") return retErr } @@ -301,7 +302,7 @@ func (slf *RedisModule) GoSetMuchStringExpire(mapInfo map[string]string, expire func (slf *RedisModule) setMuchStringByExpire(mapInfo map[string]string, expire string) error { if len(mapInfo) <= 0 { - service.GetLogger().Printf(service.LEVER_ERROR, "setMuchStringByExpire Info Is Empty") + log.Error("setMuchStringByExpire Info Is Empty") return errors.New("setMuchStringByExpire Info Is Empty") } @@ -324,7 +325,7 @@ func (slf *RedisModule) setMuchStringByExpire(mapInfo map[string]string, expire _, err = conn.Do("EXEC") if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "setMuchStringByExpire fail,reason:%v", err) + log.Error("setMuchStringByExpire fail,reason:%v", err) } return err @@ -341,7 +342,7 @@ func (slf *RedisModule) GetString(key string) (string, error) { ret, err := conn.Do("GET", key) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetString fail,reason:%v", err) + log.Error("GetString fail,reason:%v", err) return "", err } @@ -353,7 +354,7 @@ func (slf *RedisModule) GetString(key string) (string, error) { str, ok := ret.([]byte) if !ok { err = errors.New("GetString redis data is error") - service.GetLogger().Printf(service.LEVER_ERROR, "GetString redis data is error") + log.Error("GetString redis data is error") return "", err } @@ -371,7 +372,7 @@ func (slf *RedisModule) GetStringJSON(key string, st interface{}) error { ret, err := conn.Do("GET", key) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetStringJSON fail,reason:%v", err) + log.Error("GetStringJSON fail,reason:%v", err) return err } @@ -383,12 +384,12 @@ func (slf *RedisModule) GetStringJSON(key string, st interface{}) error { str, ok := ret.([]byte) if !ok { err = errors.New("GetStringJSON redis data is error!") - service.GetLogger().Printf(service.LEVER_ERROR, "GetStringJSON redis data is error!") + log.Error("GetStringJSON redis data is error!") return err } if err = json.Unmarshal(str, st); err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetStringJSON fail json.Unmarshal is error:%s,%s,reason:%v", key, string(str), err) + log.Error("GetStringJSON fail json.Unmarshal is error:%s,%s,reason:%v", key, string(str), err) return err } @@ -413,7 +414,7 @@ func (slf *RedisModule) GetMuchString(keys []string) (retMap map[string]string, // 开始Send数据 err = conn.Send("MULTI") if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetMuchString fail %v", err) + log.Error("GetMuchString fail %v", err) return nil, err } for _, val := range keys { @@ -423,7 +424,7 @@ func (slf *RedisModule) GetMuchString(keys []string) (retMap map[string]string, ret, err := conn.Do("EXEC") if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetMuchString fail %v", err) + log.Error("GetMuchString fail %v", err) return } @@ -455,7 +456,7 @@ func (slf *RedisModule) GetMuchString(keys []string) (retMap map[string]string, func (slf *RedisModule) GetMuchStringJSON(keys map[string]interface{}) error { if len(keys) <= 0 { err := errors.New("GetMuchStringJSON fail key is empty") - service.GetLogger().Printf(service.LEVER_ERROR, "GetMuchStringJSON fail key is empty") + log.Error("GetMuchStringJSON fail key is empty") return err } conn, err := slf.getConn() @@ -476,7 +477,7 @@ func (slf *RedisModule) GetMuchStringJSON(keys map[string]interface{}) error { ret, err := conn.Do("EXEC") if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetMuchStringJSON fail, reason:%v", err) + log.Error("GetMuchStringJSON fail, reason:%v", err) return err } @@ -496,7 +497,7 @@ func (slf *RedisModule) GetMuchStringJSON(keys map[string]interface{}) error { err = json.Unmarshal(strVal, keys[tempKeys[index]]) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetMuchStringJSON Unmarshal fail, reason:%v", err) + log.Error("GetMuchStringJSON Unmarshal fail, reason:%v", err) return err } } @@ -514,7 +515,7 @@ func (slf *RedisModule) ExistsKey(key string) (bool, error) { ret, err := conn.Do("EXISTS", key) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "ExistsKey fail, reason:%v", err) + log.Error("ExistsKey fail, reason:%v", err) return false, err } retValue, ok := ret.(int64) @@ -537,7 +538,7 @@ func (slf *RedisModule) DelString(key string) error { ret, err := conn.Do("DEL", key) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "DelString fail, reason:%v", err) + log.Error("DelString fail, reason:%v", err) return err } @@ -613,7 +614,7 @@ func (slf *RedisModule) DelMuchString(keys []string) (map[string]bool, error) { ret, err := conn.Do("EXEC") if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "DelMuchString fail,reason:%v", err) + log.Error("DelMuchString fail,reason:%v", err) return nil, err } @@ -652,7 +653,7 @@ func (slf *RedisModule) SetHash(redisKey, hashKey, value string) error { _, retErr := conn.Do("HSET", redisKey, hashKey, value) if retErr != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "SetHash fail,reason:%v", retErr) + log.Error("SetHash fail,reason:%v", retErr) } return retErr @@ -686,7 +687,7 @@ func (slf *RedisModule) GetAllHashJSON(redisKey string) (map[string]string, erro value, err := conn.Do("HGETALL", redisKey) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetAllHashJSON fail,reason:%v", err) + log.Error("GetAllHashJSON fail,reason:%v", err) return nil, err } @@ -697,7 +698,7 @@ func (slf *RedisModule) GetAllHashJSON(redisKey string) (map[string]string, erro func (slf *RedisModule) GetHashValueByKey(redisKey string, fieldKey string) (string, error) { if redisKey == "" || fieldKey == "" { - service.GetLogger().Printf(service.LEVER_ERROR, "GetHashValueByKey key is empty!") + log.Error("GetHashValueByKey key is empty!") return "", errors.New("Key Is Empty") } conn, err := slf.getConn() @@ -708,7 +709,7 @@ func (slf *RedisModule) GetHashValueByKey(redisKey string, fieldKey string) (str value, err := conn.Do("HGET", redisKey, fieldKey) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetHashValueByKey fail,reason:%v", err) + log.Error("GetHashValueByKey fail,reason:%v", err) return "", err } if value == nil { @@ -770,7 +771,7 @@ func (slf *RedisModule) SetMuchHashJSON(redisKey string, value map[string][]inte // 执行命令 _, err = conn.Do("EXEC") if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "SetMuchHashJSON fail,reason:%v", err) + log.Error("SetMuchHashJSON fail,reason:%v", err) } return err } @@ -841,7 +842,7 @@ func (slf *RedisModule) DelMuchHash(redisKey string, hsahKey []string) error { _, retErr := conn.Do("HDEL", arg...) if retErr != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "DelMuchHash fail,reason:%v", retErr) + log.Error("DelMuchHash fail,reason:%v", retErr) } return retErr } @@ -883,7 +884,7 @@ func (slf *RedisModule) setList(key string, value []string, setType string) erro } _, retErr := conn.Do(setType, arg...) if retErr != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "setList fail,reason:%v", retErr) + log.Error("setList fail,reason:%v", retErr) } return retErr } @@ -918,7 +919,7 @@ func (slf *RedisModule) SetListJSONLpush(key string, value interface{}) error { tempVal := []string{string(temp)} err = slf.setList(key, tempVal, "LPUSH") } else { - service.GetLogger().Printf(service.LEVER_ERROR, "SetListJSONLpush fail,reason:%v", err) + log.Error("SetListJSONLpush fail,reason:%v", err) } return err } @@ -955,7 +956,7 @@ func (slf *RedisModule) SetMuchListJSONLpush(key string, value []interface{}) er for _, val := range value { temp, err := json.Marshal(val) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "SetMuchListJSONLpush fail,reason:%v", err) + log.Error("SetMuchListJSONLpush fail,reason:%v", err) return err } @@ -998,7 +999,7 @@ func (slf *RedisModule) SetListJSONRpush(key string, value interface{}) error { tempVal := []string{string(temp)} err = slf.setList(key, tempVal, "RPUSH") } else { - service.GetLogger().Printf(service.LEVER_ERROR, "SetListJSONRpush fail,reason:%v", err) + log.Error("SetListJSONRpush fail,reason:%v", err) } return err @@ -1052,7 +1053,7 @@ func (slf *RedisModule) Lrange(key string, start, end int) ([]string, error) { reply, err := conn.Do("lrange", key, start, end) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "SetListJSONRpush fail,reason:%v", err) + log.Error("SetListJSONRpush fail,reason:%v", err) return nil, err } @@ -1069,7 +1070,7 @@ func (slf *RedisModule) GetListLen(key string) (int, error) { reply, err := conn.Do("LLEN", key) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "GetListLen fail,reason:%v", err) + log.Error("GetListLen fail,reason:%v", err) return -1, err } return redis.Int(reply, err) @@ -1086,7 +1087,7 @@ func (slf *RedisModule) RPOPListValue(key string) error { _, err = conn.Do("RPOP", key, 100) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "RPOPListValue fail,reason:%v", err) + log.Error("RPOPListValue fail,reason:%v", err) return err } return nil @@ -1103,7 +1104,7 @@ func (slf *RedisModule) LtrimList(key string, start, end int) error { _, err = conn.Do("LTRIM", key, start, end) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "LtrimListValue fail,reason:%v", err) + log.Error("LtrimListValue fail,reason:%v", err) return err } return nil @@ -1124,7 +1125,7 @@ func (slf *RedisModule) ZADDInsertJson(key string, score float64, value interfac } _, err = conn.Do("ZADD", key, score, JsonValue) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "ZADDInsertJson fail,reason:%v", err) + log.Error("ZADDInsertJson fail,reason:%v", err) return err } return nil @@ -1140,7 +1141,7 @@ func (slf *RedisModule) ZADDInsert(key string, score float64, Data interface{}) _, err = conn.Do("ZADD", key, score, Data) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "ZADDInsert fail,reason:%v", err) + log.Error("ZADDInsert fail,reason:%v", err) return err } return nil @@ -1444,13 +1445,13 @@ func (slf *RedisModule) HincrbyHashInt(redisKey, hashKey string, value int) erro _, retErr := conn.Do("HINCRBY", redisKey, hashKey, value) if retErr != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "HincrbyHashInt fail,reason:%v", retErr) + log.Error("HincrbyHashInt fail,reason:%v", retErr) } return retErr } - func (slf *RedisModule) EXPlREInsert(key string, TTl int) error { +func (slf *RedisModule) EXPlREInsert(key string, TTl int) error { conn, err := slf.getConn() if err != nil { return err @@ -1459,7 +1460,7 @@ func (slf *RedisModule) HincrbyHashInt(redisKey, hashKey string, value int) erro _, err = conn.Do("expire", key, TTl) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "expire fail,reason:%v", err) + log.Error("expire fail,reason:%v", err) return err } return nil @@ -1486,7 +1487,7 @@ func (slf *RedisModule) Keys(key string) ([]string, error) { ret, err := conn.Do("KEYS", key) if err != nil { - service.GetLogger().Printf(service.LEVER_ERROR, "KEYS fail, reason:%v", err) + log.Error("KEYS fail, reason:%v", err) return nil, err } retList, ok := ret.([]interface{}) diff --git a/sysmodule/RedisModule_test.go b/sysmodule/RedisModule_test.go deleted file mode 100644 index f80d2f3..0000000 --- a/sysmodule/RedisModule_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package sysmodule - -import ( - "fmt" - "testing" - "time" -) - -type CTestJson struct { - A string - B string -} - -func TestRedisModule(t *testing.T) { - - var cfg ConfigRedis - var redsmodule RedisModule - - cfg.IP = "127.0.0.1" - cfg.Password = "" - cfg.Port = "6379" - cfg.IdleTimeout = 2 - cfg.MaxActive = 3 - cfg.MaxIdle = 3 - cfg.DbIndex = 15 - redsmodule.Init(&cfg) - - //GoSetString - var retErr RetError - redsmodule.GoSetString("testkey", "testvalue", &retErr) - ret1, err1 := redsmodule.GetString("testkey") - - //GoSetStringExpire - redsmodule.GoSetStringExpire("setstring_key", "value11", "1", &retErr) - time.Sleep(time.Second * 2) - ret2, err2 := redsmodule.GetString("setstring_key") - fmt.Print(ret1, err1, retErr.Get(), "\n") - fmt.Print(ret2, err2, "\n") - - //GoSetStringJSON - var testjson CTestJson - testjson.A = "A value" - testjson.B = "B value" - - var retErr2 RetError - redsmodule.GoSetStringJSON("setstring_key_json", &testjson, &retErr) - - //GoSetStringJSONExpire - redsmodule.GoSetStringJSONExpire("setstring_key_json_expire", &testjson, "10", &retErr2) - fmt.Print(retErr.Get(), "\n") - fmt.Print(retErr2.Get(), "\n") - var testjson2 CTestJson - err := redsmodule.GetStringJSON("setstring_key_json", &testjson2) - fmt.Print(err, "\n", testjson2, "\n") - - //GoSetMuchString/GoSetMuchStringExpire - mapInfo := make(map[string]string) - mapInfo["A"] = "A_value" - mapInfo["B"] = "B_value" - mapInfo["C"] = "C_value" - redsmodule.GoSetMuchString(mapInfo, &retErr) - redsmodule.GoSetMuchStringExpire(mapInfo, "100", &retErr) - var keylist []string - keylist = append(keylist, "A", "C") - mapInfo, _ = redsmodule.GetMuchString(keylist) - fmt.Print(retErr.Get(), "\n", mapInfo, "\n") - - //GoDelString - redsmodule.GoDelString("setstring_key_json", &retErr) - fmt.Print(retErr.Get(), "\n") - - var retMapStr RetMapString - redsmodule.GoDelMuchString(keylist, &retMapStr) - err2, mapstr := retMapStr.Get() - fmt.Print(err2, "\n", mapstr, "\n") - - //GoSetHash - redsmodule.GoSetHash("rediskey", "hashkey", "1111", &retErr) - ret, err := redsmodule.GetHashValueByKey("rediskey", "hashkey") - fmt.Print(retErr.Get(), ret, err) - - //GoSetHashJSON - redsmodule.GoSetHashJSON("rediskey", "hashkey2", &testjson, &retErr) - fmt.Print(retErr.Get(), "\n") - - //SetMuchHashJSON - var mapHashJson map[string][]interface{} - var listInterface []interface{} - mapHashJson = make(map[string][]interface{}) - listInterface = append(listInterface, testjson, testjson) - - mapHashJson["key3"] = listInterface - mapHashJson["key4"] = listInterface - - redsmodule.GoSetMuchHashJSON("rediskey", mapHashJson, &retErr) - fmt.Print(retErr.Get(), "\n") - - //GoDelHash - redsmodule.GoDelHash("rediskey", "hashkey", &retErr) - fmt.Print(retErr.Get(), "\n") - - //GoDelMuchHash - var keys []string - keys = append(keys, "hashkey", "hashkey2") - - redsmodule.GoDelMuchHash("rediskey", keys, &retErr) - fmt.Print(retErr.Get(), "\n") - - //GoSetListLpush - redsmodule.GoSetListLpush("setlistKey", "list1", &retErr) - fmt.Print(retErr.Get(), "\n") - redsmodule.GoSetListLpush("setlistKey", "list2", &retErr) - fmt.Print(retErr.Get(), "\n") - redsmodule.GoSetListLpush("setlistKey", "list3", &retErr) - fmt.Print(retErr.Get(), "\n") -} diff --git a/sysmodule/SystemModuleDef.go b/sysmodule/SystemModuleDef.go deleted file mode 100644 index f4380f1..0000000 --- a/sysmodule/SystemModuleDef.go +++ /dev/null @@ -1,7 +0,0 @@ -package sysmodule - -//等级从低到高 -const ( - SYS_LOG = 1 - SYS_TEST = 2 -) diff --git a/sysservice/logservice.go b/sysservice/logservice.go deleted file mode 100644 index af50b75..0000000 --- a/sysservice/logservice.go +++ /dev/null @@ -1,37 +0,0 @@ -package sysservice - -import ( - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysmodule" -) - -type LogService struct { - service.BaseService - logmodule *sysmodule.LogModule -} - -func (slf *LogService) InitLog(logservicename string, logFilePrefix string, openLevel uint) { - slf.SetServiceName(logservicename) - slf.logmodule = &sysmodule.LogModule{} - slf.logmodule.Init(logFilePrefix, openLevel) -} - -func (slf *LogService) Printf(level uint, format string, v ...interface{}) { - slf.logmodule.Printf(level, format, v...) -} - -func (slf *LogService) Print(level uint, v ...interface{}) { - slf.logmodule.Print(level, v...) -} - -func (slf *LogService) AppendCallDepth(calldepth int) { - slf.logmodule.AppendCallDepth(calldepth) -} - -func (slf *LogService) SetLogLevel(level uint) { - slf.logmodule.SetLogLevel(level) -} - -func (slf *LogService) SetListenLogFunc(listenFun sysmodule.FunListenLog) { - slf.logmodule.SetListenLogFunc(listenFun) -} diff --git a/sysservice/originhttp/httpserverervice.go b/sysservice/originhttp/httpserverervice.go deleted file mode 100644 index d9e126a..0000000 --- a/sysservice/originhttp/httpserverervice.go +++ /dev/null @@ -1,511 +0,0 @@ -package originhttp - -import ( - "encoding/json" - "errors" - "fmt" - "io" - "io/ioutil" - "net/http" - - "os" - "reflect" - "runtime" - "strings" - "time" - - "github.com/duanhf2012/origin/sysmodule" - - "github.com/duanhf2012/origin/rpc" - - "github.com/duanhf2012/origin/cluster" - "github.com/duanhf2012/origin/network" - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/util/uuid" -) - -type HttpRedirectData struct { - Url string - //Cookies map[string]string - - CookieList []*http.Cookie -} - -type HttpRequest struct { - Header http.Header - Body string - - ParamStr string //http://127.0.0.1:7001/aaa/bbb?aa=1中的aa=1部分 - mapParam map[string]string - URL string - //Req http.Request -} - -type HttpRespone struct { - Respone []byte - RedirectData HttpRedirectData - //Resp http.ResponseWriter -} - -type ServeHTTPRouterMux struct { - httpfiltrateList []HttpFiltrate - allowOrigin bool -} -type ControllerMapsType map[string]reflect.Value - -type HttpServerService struct { - service.BaseService - httpserver network.HttpServer - port uint16 - - controllerMaps ControllerMapsType - certfile string - keyfile string - ishttps bool - serverHTTPMux ServeHTTPRouterMux -} - -type RouterMatchData struct { - callpath string - matchURL string - routerType int8 //0表示函数调用 1表示静态资源 -} - -type RouterStaticResoutceData struct { - localpath string - method string -} - -type HTTP_METHOD int - -const ( - METHOD_GET HTTP_METHOD = iota - METHOD_POST HTTP_METHOD = 1 - //METHOD_PUT HTTP_METHOD = 2 -) - -var bPrintRequestTime bool - -var postAliasUrl map[string]map[string]RouterMatchData //url地址,对应本service地址 -var staticRouterResource map[string]RouterStaticResoutceData - -func init() { - postAliasUrl = make(map[string]map[string]RouterMatchData) - postAliasUrl["GET"] = make(map[string]RouterMatchData) - postAliasUrl["POST"] = make(map[string]RouterMatchData) - - staticRouterResource = make(map[string]RouterStaticResoutceData) -} - -type HttpHandle func(request *HttpRequest, resp *HttpRespone) error - -func AnalysisRouterUrl(url string) (string, error) { - - //替换所有空格 - url = strings.ReplaceAll(url, " ", "") - if len(url) <= 1 || url[0] != '/' { - return "", fmt.Errorf("url %s format is error!", url) - } - - //去掉尾部的/ - return strings.Trim(url, "/"), nil -} - -func (slf *HttpRequest) Query(key string) (string, bool) { - if slf.mapParam == nil { - slf.mapParam = make(map[string]string) - //分析字符串 - slf.ParamStr = strings.Trim(slf.ParamStr, "/") - paramStrList := strings.Split(slf.ParamStr, "&") - for _, val := range paramStrList { - Index := strings.Index(val, "=") - if Index >= 0 { - slf.mapParam[val[0:Index]] = val[Index+1:] - } - } - } - - ret, ok := slf.mapParam[key] - return ret, ok -} - -func Request(method HTTP_METHOD, url string, handle HttpHandle) error { - fnpath := runtime.FuncForPC(reflect.ValueOf(handle).Pointer()).Name() - - sidx := strings.LastIndex(fnpath, "*") - if sidx == -1 { - return errors.New(fmt.Sprintf("http post func path is error, %s\n", fnpath)) - } - - eidx := strings.LastIndex(fnpath, "-fm") - if sidx == -1 { - return errors.New(fmt.Sprintf("http post func path is error, %s\n", fnpath)) - } - callpath := fnpath[sidx+1 : eidx] - ridx := strings.LastIndex(callpath, ")") - if ridx == -1 { - return errors.New(fmt.Sprintf("http post func path is error, %s\n", fnpath)) - } - - hidx := strings.LastIndex(callpath, "HTTP_") - if hidx == -1 { - return errors.New(fmt.Sprintf("http post func not contain HTTP_, %s\n", fnpath)) - } - - callpath = strings.ReplaceAll(callpath, ")", "") - - var r RouterMatchData - var matchURL string - var err error - r.routerType = 0 - r.callpath = "_" + callpath - matchURL, err = AnalysisRouterUrl(url) - if err != nil { - return err - } - - var strMethod string - if method == METHOD_GET { - strMethod = "GET" - } else if method == METHOD_POST { - strMethod = "POST" - } else { - return nil - } - - postAliasUrl[strMethod][matchURL] = r - - return nil -} - -func Post(url string, handle HttpHandle) error { - return Request(METHOD_POST, url, handle) -} - -func Get(url string, handle HttpHandle) error { - return Request(METHOD_GET, url, handle) -} - -func (slf *HttpServerService) OnInit() error { - slf.serverHTTPMux = ServeHTTPRouterMux{} - slf.httpserver.Init(slf.port, &slf.serverHTTPMux, 10*time.Second, 10*time.Second) - if slf.ishttps == true { - slf.httpserver.SetHttps(slf.certfile, slf.keyfile) - } - return nil -} - -func (slf *ServeHTTPRouterMux) SetAlowOrigin(allowOrigin bool) { - slf.allowOrigin = allowOrigin -} - -func (slf *ServeHTTPRouterMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if slf.allowOrigin == true { - if origin := r.Header.Get("Origin"); origin != "" { - w.Header().Set("Access-Control-Allow-Origin", "*") - w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") - w.Header().Set("Access-Control-Allow-Headers", - "Action, Module") //有使用自定义头 需要这个,Action, Module是例子 - } - } - - if r.Method == "OPTIONS" { - return - } - - methodRouter, bok := postAliasUrl[r.Method] - if bok == false { - writeRespone(w, http.StatusNotFound, fmt.Sprint("Can not support method.")) - return - } - - //权限验证 - var errRet error - for _, filter := range slf.httpfiltrateList { - ret := filter(r.URL.Path, w, r) - if ret == nil { - errRet = nil - break - } else { - errRet = ret - } - } - if errRet != nil { - writeRespone(w, http.StatusOK, errRet.Error()) - return - } - - url := strings.Trim(r.URL.Path, "/") - var strCallPath string - matchData, ok := methodRouter[url] - if ok == true { - strCallPath = matchData.callpath - } else { - //如果是资源处理 - for k, v := range staticRouterResource { - idx := strings.Index(url, k) - if idx != -1 { - staticServer(k, v, w, r) - return - } - } - - // 拼接得到rpc服务的名称 - vstr := strings.Split(url, "/") - if len(vstr) < 2 { - writeRespone(w, http.StatusNotFound, "Cannot find path.") - return - } - strCallPath = "_" + vstr[0] + ".HTTP_" + vstr[1] - } - - defer r.Body.Close() - msg, err := ioutil.ReadAll(r.Body) - if err != nil { - writeRespone(w, http.StatusBadRequest, "") - return - } - - request := HttpRequest{r.Header, string(msg), r.URL.RawQuery, nil, r.URL.Path} - var resp HttpRespone - //resp.Resp = w - timeFuncStart := time.Now() - err = cluster.InstanceClusterMgr().Call(strCallPath, &request, &resp) - - timeFuncPass := time.Since(timeFuncStart) - if bPrintRequestTime { - service.GetLogger().Printf(service.LEVER_INFO, "HttpServer Time : %s url : %s\n", timeFuncPass, strCallPath) - } - if err != nil { - writeRespone(w, http.StatusBadRequest, fmt.Sprint(err)) - } else { - if resp.RedirectData.Url != "" { - resp.redirects(&w, r) - } else { - writeRespone(w, http.StatusOK, string(resp.Respone)) - } - - } -} - -// CkResourceDir 检查静态资源文件夹路径 -func SetStaticResource(method HTTP_METHOD, urlpath string, dirname string) error { - _, err := os.Stat(dirname) - if err != nil { - return err - } - matchURL, berr := AnalysisRouterUrl(urlpath) - if berr != nil { - return berr - } - - var routerData RouterStaticResoutceData - if method == METHOD_GET { - routerData.method = "GET" - } else if method == METHOD_POST { - routerData.method = "POST" - } else { - return nil - } - routerData.localpath = dirname - - staticRouterResource[matchURL] = routerData - return nil -} - -func writeRespone(w http.ResponseWriter, status int, msg string) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.WriteHeader(status) - w.Write([]byte(msg)) -} - -type HttpFiltrate func(path string, w http.ResponseWriter, r *http.Request) error - -func (slf *HttpServerService) AppendHttpFiltrate(fun HttpFiltrate) bool { - slf.serverHTTPMux.httpfiltrateList = append(slf.serverHTTPMux.httpfiltrateList, fun) - - return false -} - -func (slf *HttpServerService) OnRun() bool { - - slf.httpserver.Start() - return false -} - -func NewHttpServerService(port uint16) *HttpServerService { - http := new(HttpServerService) - - http.port = port - return http -} - -func (slf *HttpServerService) OnDestory() error { - return nil -} - -func (slf *HttpServerService) OnSetupService(iservice service.IService) { - rpc.RegisterName(iservice.GetServiceName(), "HTTP_", iservice) -} - -func (slf *HttpServerService) OnRemoveService(iservice service.IService) { - return -} - -func (slf *HttpServerService) SetPrintRequestTime(isPrint bool) { - bPrintRequestTime = isPrint -} - -func staticServer(routerUrl string, routerData RouterStaticResoutceData, w http.ResponseWriter, r *http.Request) { - upath := r.URL.Path - idx := strings.Index(upath, routerUrl) - subPath := strings.Trim(upath[idx+len(routerUrl):], "/") - - destLocalPath := routerData.localpath + subPath - - writeResp := func(status int, msg string) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.WriteHeader(status) - w.Write([]byte(msg)) - } - - switch r.Method { - //获取资源 - case "GET": - //判断文件夹是否存在 - _, err := os.Stat(destLocalPath) - if err == nil { - http.ServeFile(w, r, destLocalPath) - } else { - writeResp(http.StatusNotFound, "") - return - } - //上传资源 - case "POST": - // 在这儿处理例外路由接口 - /* - var errRet error - for _, filter := range slf.httpfiltrateList { - ret := filter(r.URL.Path, w, r) - if ret == nil { - errRet = nil - break - } else { - errRet = ret - } - } - if errRet != nil { - w.Write([]byte(errRet.Error())) - return - }*/ - r.ParseMultipartForm(32 << 20) // max memory is set to 32MB - resourceFile, resourceFileHeader, err := r.FormFile("file") - if err != nil { - fmt.Println(err) - writeResp(http.StatusNotFound, err.Error()) - return - } - defer resourceFile.Close() - //重新拼接文件名 - imgFormat := strings.Split(resourceFileHeader.Filename, ".") - if len(imgFormat) < 2 { - writeResp(http.StatusNotFound, "not a file") - return - } - filePrefixName := uuid.Rand().HexEx() - fileName := filePrefixName + "." + imgFormat[len(imgFormat)-1] - //创建文件 - localpath := fmt.Sprintf("%s%s", destLocalPath, fileName) - localfd, err := os.OpenFile(localpath, os.O_WRONLY|os.O_CREATE, 0666) - if err != nil { - fmt.Println(err) - writeResp(http.StatusNotFound, "upload fail") - return - } - defer localfd.Close() - io.Copy(localfd, resourceFile) - writeResp(http.StatusOK, upath+"/"+fileName) - } - -} - -func (slf *HttpServerService) GetMethod(strCallPath string) (*reflect.Value, error) { - value, ok := slf.controllerMaps[strCallPath] - if ok == false { - err := fmt.Errorf("not find api") - return nil, err - } - - return &value, nil -} - -func (slf *HttpServerService) SetHttps(certfile string, keyfile string) bool { - if certfile == "" || keyfile == "" { - return false - } - - slf.ishttps = true - slf.certfile = certfile - slf.keyfile = keyfile - - return true -} - -//序列化后写入Respone -func (slf *HttpRespone) WriteRespne(v interface{}) error { - StrRet, retErr := json.Marshal(v) - if retErr != nil { - slf.Respone = []byte(`{"Code": 2,"Message":"service error"}`) - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "Json Marshal Error:%v\n", retErr) - } else { - slf.Respone = StrRet - } - - return retErr -} - -func (slf *HttpRespone) WriteRespones(Code int32, Msg string, Data interface{}) { - - var StrRet string - //判断是否有错误码 - if Code > 0 { - StrRet = fmt.Sprintf(`{"RCode": %d,"RMsg":"%s"}`, Code, Msg) - } else { - if Data == nil { - if Msg != "" { - StrRet = fmt.Sprintf(`{"RCode": 0,"RMsg":"%s"}`, Msg) - } else { - StrRet = `{"RCode": 0}` - } - } else { - if reflect.TypeOf(Data).Kind() == reflect.String { - StrRet = fmt.Sprintf(`{"RCode": %d , "Data": "%s"}`, Code, Data) - } else { - JsonRet, Err := json.Marshal(Data) - if Err != nil { - service.GetLogger().Printf(sysmodule.LEVER_ERROR, "common WriteRespone Json Marshal Err %+v", Data) - } else { - StrRet = fmt.Sprintf(`{"RCode": %d , "Data": %s}`, Code, JsonRet) - } - } - } - } - slf.Respone = []byte(StrRet) -} - -func (slf *HttpRespone) Redirect(url string, cookieList []*http.Cookie) { - slf.RedirectData.Url = url - slf.RedirectData.CookieList = cookieList -} - -func (slf *HttpRespone) redirects(w *http.ResponseWriter, req *http.Request) { - if slf.RedirectData.CookieList != nil { - for _, v := range slf.RedirectData.CookieList { - http.SetCookie(*w, v) - } - } - - http.Redirect(*w, req, slf.RedirectData.Url, - // see @andreiavrammsd comment: often 307 > 301 - http.StatusTemporaryRedirect) -} diff --git a/sysservice/pprofservice.go b/sysservice/pprofservice.go deleted file mode 100644 index 41f8b1d..0000000 --- a/sysservice/pprofservice.go +++ /dev/null @@ -1,73 +0,0 @@ -package sysservice - -import ( - "encoding/json" - "fmt" - "runtime/pprof" - "time" - - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/sysservice/originhttp" -) - -type PProfService struct { - service.BaseService - fisttime int -} - -type ProfileData struct { - Name string - Count int -} - -type Profilestruct struct { - Fisttime int - ProfileList []ProfileData -} - -func (slf *PProfService) OnInit() error { - slf.fisttime = (int)(time.Now().UnixNano()) - return nil -} - -func (slf *PProfService) GetPprof() ([]byte, error) { - var pfiles Profilestruct - pfiles.Fisttime = slf.fisttime - - for _, p := range pprof.Profiles() { - pfiles.ProfileList = append(pfiles.ProfileList, ProfileData{ - Name: p.Name(), - Count: p.Count(), - }) - } - - return json.Marshal(pfiles) -} - -func (slf *PProfService) HTTP_DebugPProf(request *originhttp.HttpRequest, resp *originhttp.HttpRespone) error { - var err error - resp.Respone, err = slf.GetPprof() - if err != nil { - resp.Respone = []byte(fmt.Sprint(err)) - } - return nil -} - -func (slf *PProfService) RPC_DebugPProf(arg *string, ret *Profilestruct) error { - - ret.Fisttime = slf.fisttime - for _, p := range pprof.Profiles() { - ret.ProfileList = append(ret.ProfileList, ProfileData{ - Name: p.Name(), - Count: p.Count(), - }) - } - - return nil -} - -func (slf *PProfService) HTTP_Test(request *originhttp.HttpRequest, resp *originhttp.HttpRespone) error { - - resp.Respone = []byte(request.Body) - return nil -} diff --git a/sysservice/synccacheservice/synccacheservice.go b/sysservice/synccacheservice/synccacheservice.go deleted file mode 100644 index bec5309..0000000 --- a/sysservice/synccacheservice/synccacheservice.go +++ /dev/null @@ -1,167 +0,0 @@ -package synccacheservice - -import ( - "encoding/json" - "errors" - "fmt" - "time" - - "github.com/duanhf2012/origin/cluster" - "github.com/duanhf2012/origin/service" - "github.com/duanhf2012/origin/util" -) - -const ( - MAX_SYNC_DATA_CHAN_NUM = 10000 -) - -//CReportService ... -type CSyncCacheService struct { - service.BaseService - mapCache util.Map - syncQueue *util.SyncQueue - - nodeIdList []int - syncDataChanList []chan *SyncCacheData -} - -type SyncCacheData struct { - OperType int8 //0 表示添加或者更新 1表示删除 - Key string - Val string - Wxpire int32 //ms - NodeIdList []int - reTryCount uint32 - reTryTime int64 -} - -//OnInit ... -func (slf *CSyncCacheService) OnInit() error { - slf.syncQueue = util.NewSyncQueue() - var callServiceName string - slf.nodeIdList = cluster.InstanceClusterMgr().GetNodeList("CSyncCacheService.RPC_SyncString", &callServiceName, nil) - for _, nodeId := range slf.nodeIdList { - syncCacheData := make(chan *SyncCacheData, MAX_SYNC_DATA_CHAN_NUM) - slf.syncDataChanList = append(slf.syncDataChanList, syncCacheData) - go slf.syncRouter(nodeId, syncCacheData) - } - - return nil -} - -func (slf *CSyncCacheService) syncRouter(nodeId int, syncDataChan chan *SyncCacheData) error { - - tryCount := 0 - for { - select { - case <-slf.ExitChan: - break - case data := <-syncDataChan: - var ret int - cluster.CallNode(nodeId, "CSyncCacheService.RPC_SyncString", data, &ret) - if ret == 0 { - if tryCount < 3 { - time.Sleep(800 * time.Millisecond) - } else { - time.Sleep(1500 * time.Millisecond) - } - - slf.tryPushSyncData(syncDataChan, data) - tryCount++ - } else { - tryCount = 0 - } - } - } - - return nil -} - -func (slf *CSyncCacheService) tryPushSyncData(syncDataChan chan *SyncCacheData, syncData *SyncCacheData) bool { - if len(syncDataChan) >= MAX_SYNC_DATA_CHAN_NUM { - return false - } - syncDataChan <- syncData - - return true -} - -func (slf *CSyncCacheService) RPC_SyncString(request *SyncCacheData, ret *int) error { - - if request.OperType == 0 { - slf.mapCache.Set(request.Key, request.Val) - } else { - slf.mapCache.Del(request.Key) - } - - *ret = 1 - return nil -} - -func SetStringJson(key string, val interface{}) error { - - byteBuf, err := json.Marshal(val) - if err != nil { - return err - } - - SetString(key, string(byteBuf)) - return nil -} - -func GetStringJson(key string, val interface{}) error { - ret, err := GetString(key) - if err != nil { - return err - } - - err = json.Unmarshal([]byte(ret), val) - return err -} - -func DelString(key string) error { - pubcacheservice := service.InstanceServiceMgr().FindService("CSyncCacheService") - if pubcacheservice == nil { - return errors.New("Cannot find CSyncCacheService") - } - - pPubCacheService := pubcacheservice.(*CSyncCacheService) - syncCacheData := SyncCacheData{1, key, "", 0, pPubCacheService.nodeIdList[:], 0, 0} - - for _, syncChan := range pPubCacheService.syncDataChanList { - pPubCacheService.tryPushSyncData(syncChan, &syncCacheData) - } - - return nil -} - -func SetString(key string, val string) error { - pubcacheservice := service.InstanceServiceMgr().FindService("CSyncCacheService") - if pubcacheservice == nil { - return errors.New("Cannot find CSyncCacheService") - } - - //同步所有远程结点 - pPubCacheService := pubcacheservice.(*CSyncCacheService) - syncCacheData := SyncCacheData{0, key, val, 0, pPubCacheService.nodeIdList[:], 0, 0} - for _, syncChan := range pPubCacheService.syncDataChanList { - pPubCacheService.tryPushSyncData(syncChan, &syncCacheData) - } - - return nil -} - -func GetString(key string) (string, error) { - pubcacheservice := service.InstanceServiceMgr().FindService("CSyncCacheService") - if pubcacheservice == nil { - return "", errors.New("Cannot find CSyncCacheService") - } - - pPubCacheService := pubcacheservice.(*CSyncCacheService) - ret := pPubCacheService.mapCache.Get(key) - if ret == nil { - return "", errors.New(fmt.Sprintf("Cannot find key :%s", key)) - } - - return ret.(string), nil -} diff --git a/sysservice/tcpservice.go b/sysservice/tcpservice.go new file mode 100644 index 0000000..2c29ce1 --- /dev/null +++ b/sysservice/tcpservice.go @@ -0,0 +1,137 @@ +package sysservice + +import ( + "fmt" + "github.com/duanhf2012/originnet/event" + "github.com/duanhf2012/originnet/log" + "github.com/duanhf2012/originnet/network" + "github.com/duanhf2012/originnet/service" + "sync" +) + +type TcpService struct { + tcpServer network.TCPServer + service.Service + + tcpService *TcpService + mapClientLocker sync.RWMutex + mapClient map[uint64] *Client + initClientId uint64 + process network.Processor +} + +const Default_MaxConnNum = 3000 +const Default_PendingWriteNum = 10000 +const Default_LittleEndian = false +const Default_MinMsgLen = 2 +const Default_MaxMsgLen = 65535 + + + +func (slf *TcpService) OnInit() error{ + iConfig := slf.GetServiceCfg() + if iConfig == nil { + return fmt.Errorf("%s service config is error!",slf.GetName()) + } + tcpCfg := iConfig.(map[string]interface{}) + addr,ok := tcpCfg["ListenAddr"] + if ok == false { + return fmt.Errorf("%s service config is error!",slf.GetName()) + } + slf.tcpServer.Addr = addr.(string) + slf.tcpServer.MaxConnNum = Default_MaxConnNum + slf.tcpServer.PendingWriteNum = Default_PendingWriteNum + slf.tcpServer.LittleEndian = Default_LittleEndian + slf.tcpServer.MinMsgLen = Default_MinMsgLen + slf.tcpServer.MaxMsgLen = Default_MaxMsgLen + MaxConnNum,ok := tcpCfg["MaxConnNum"] + if ok == true { + slf.tcpServer.MaxConnNum = int(MaxConnNum.(float64)) + } + PendingWriteNum,ok := tcpCfg["PendingWriteNum"] + if ok == true { + slf.tcpServer.PendingWriteNum = int(PendingWriteNum.(float64)) + } + LittleEndian,ok := tcpCfg["LittleEndian"] + if ok == true { + slf.tcpServer.LittleEndian = LittleEndian.(bool) + } + MinMsgLen,ok := tcpCfg["MinMsgLen"] + if ok == true { + slf.tcpServer.MinMsgLen = uint32(MinMsgLen.(float64)) + } + MaxMsgLen,ok := tcpCfg["MaxMsgLen"] + if ok == true { + slf.tcpServer.MaxMsgLen = uint32(MaxMsgLen.(float64)) + } + slf.tcpServer.NewAgent =slf.NewClient + slf.tcpServer.Start() + //加载配置 + return nil +} + +func (slf *TcpService) SetProcessor(process network.Processor){ + slf.process = process +} + +func (slf *TcpService) NewClient(conn *network.TCPConn) network.Agent { + slf.mapClientLocker.Lock() + defer slf.mapClientLocker.Unlock() + + for { + slf.initClientId+=1 + _,ok := slf.mapClient[slf.initClientId] + if ok == true { + continue + } + + pClient := &Client{tcpConn:conn} + slf.mapClient[slf.initClientId] = pClient + return pClient + } + + return nil +} + + + +type Client struct { + id uint64 + tcpConn *network.TCPConn + tcpService *TcpService +} + +type TcpPack struct { + ClientId uint64 + Data interface{} +} + +func (slf *Client) GetId() uint64 { + return slf.id +} + +func (slf *Client) Run() { + slf.tcpService.GetEventReciver().NotifyEvent(&event.Event{Type:event.Sys_Event_Tcp_Connected,Data:&TcpPack{ClientId:slf.id}}) + for{ + bytes,err := slf.tcpConn.ReadMsg() + if err != nil { + log.Debug("read client id %d is error",err) + break + } + data,err:=slf.tcpService.process.Unmarshal(bytes) + if err != nil { + log.Debug("process.Unmarshal is error:%+v",err) + continue + } + + + slf.tcpService.GetEventReciver().NotifyEvent(&event.Event{Type:event.Sys_Event_Tcp_RecvPack,Data:&TcpPack{ClientId:slf.id,Data:data}}) + } +} + +func (slf *Client) OnClose(){ + slf.tcpService.GetEventReciver().NotifyEvent(&event.Event{Type:event.Sys_Event_Tcp_DisConnected,Data:&TcpPack{ClientId:slf.id}}) + slf.tcpService.mapClientLocker.Lock() + defer slf.tcpService.mapClientLocker.Unlock() + delete (slf.tcpService.mapClient,slf.GetId()) +} diff --git a/sysservice/tcpsocketpbservice.go b/sysservice/tcpsocketpbservice.go deleted file mode 100644 index f0be692..0000000 --- a/sysservice/tcpsocketpbservice.go +++ /dev/null @@ -1,172 +0,0 @@ -package sysservice - -import ( - "errors" - "github.com/duanhf2012/origin/network" - "github.com/duanhf2012/origin/service" - "github.com/golang/protobuf/proto" - "reflect" -) - -type TcpSocketPbService struct { - service.BaseService - listenaddr string - tcpsocketserver network.TcpSocketServer - MsgProcessor -} - - -type MessageHandler func(clientid uint64,msgtype uint16,msg proto.Message) -type MessageRecvHandler func(pClient *network.SClient,pPack *network.MsgBasePack) -type EventHandler func(clientid uint64) -type ExceptMsgHandler func(clientid uint64,pPack *network.MsgBasePack,err error) - -type MsgProcessor struct { - mapMsg map[uint16]MessageInfo - connEvent EventHandler - disconnEvent EventHandler - exceptMsgHandler ExceptMsgHandler - messageRecvHandler MessageRecvHandler -} - - -func (slf *MsgProcessor) InitProcessor(){ - slf.mapMsg = make(map[uint16]MessageInfo) -} - -func (slf *MsgProcessor) RegMessage(msgtype uint16,msg proto.Message,handle MessageHandler){ - var info MessageInfo - - info.msgType = reflect.TypeOf(msg.(proto.Message)) - info.msgHandler = handle - slf.mapMsg[msgtype] = info -} - -func (slf *MsgProcessor) RegConnectEvent(eventHandler EventHandler){ - slf.connEvent = eventHandler -} - -func (slf *MsgProcessor) RegDisconnectEvent(eventHandler EventHandler){ - slf.disconnEvent = eventHandler -} - -func (slf *MsgProcessor) RegExceptMessage(exceptMsgHandler ExceptMsgHandler){ - slf.exceptMsgHandler = exceptMsgHandler -} - -func (slf *MsgProcessor) RegRecvMessage(msgHandler MessageRecvHandler){ - slf.messageRecvHandler = msgHandler -} - -func (slf *MsgProcessor) OnExceptMsg (pClient *network.SClient,pPack *network.MsgBasePack,err error){ - if slf.exceptMsgHandler!=nil { - slf.exceptMsgHandler(pClient.GetId(),pPack,err) - }else{ - pClient.Close() - //记录日志 - service.GetLogger().Printf(service.LEVER_WARN, "OnExceptMsg packtype %d,error %+v",pPack.PackType,err) - } -} - -func NewTcpSocketPbService(listenaddr string) *TcpSocketPbService { - ts := new(TcpSocketPbService) - - ts.listenaddr = listenaddr - ts.mapMsg = make(map[uint16]MessageInfo,1) - ts.tcpsocketserver.Register(listenaddr,ts) - return ts -} - -func (slf *TcpSocketPbService) OnInit() error { - return nil -} - -func (slf *TcpSocketPbService) OnRun() bool { - slf.tcpsocketserver.Start() - - return false -} - - -type MessageInfo struct { - msgType reflect.Type - msgHandler MessageHandler -} - - -func (slf *TcpSocketPbService) RegMessage(msgtype uint16,msg proto.Message,handle MessageHandler){ - var info MessageInfo - - info.msgType = reflect.TypeOf(msg.(proto.Message)) - info.msgHandler = handle - slf.mapMsg[msgtype] = info -} - - -func (slf *TcpSocketPbService) OnConnected(pClient *network.SClient){ - if slf.connEvent!=nil { - slf.connEvent(pClient.GetId()) - } -} - -func (slf *TcpSocketPbService) OnDisconnect(pClient *network.SClient){ - if slf.disconnEvent!=nil { - slf.disconnEvent(pClient.GetId()) - } -} - - -func (slf *MsgProcessor) Handle(pClient *network.SClient,pPack *network.MsgBasePack){ - if info, ok := slf.mapMsg[pPack.PackType]; ok { - msg := reflect.New(info.msgType.Elem()).Interface() - tmp := msg.(proto.Message) - err := proto.Unmarshal(pPack.Body, tmp) - if err != nil { - slf.OnExceptMsg(pClient,pPack,err) - return - } - - info.msgHandler(pClient.GetId(),pPack.PackType, msg.(proto.Message)) - return - }else if slf.messageRecvHandler!=nil { - slf.messageRecvHandler(pClient,pPack) - return - } - - slf.OnExceptMsg(pClient,pPack,errors.New("not found PackType")) -} - - -func (slf *TcpSocketPbService) OnRecvMsg(pClient *network.SClient, pPack *network.MsgBasePack){ - slf.Handle(pClient,pPack) -} - -func DefaultTSPbService() *TcpSocketPbService{ - iservice := service.InstanceServiceMgr().FindService("TcpSocketPbService") - if iservice == nil { - return nil - } - - return iservice.(*TcpSocketPbService) -} - -func GetTcpSocketPbService(serviceName string) *TcpSocketPbService{ - iservice := service.InstanceServiceMgr().FindService(serviceName) - if iservice == nil { - return nil - } - - return iservice.(*TcpSocketPbService) -} - -func (slf *TcpSocketPbService) SendMsg(clientid uint64,packtype uint16,message proto.Message) error{ - return slf.tcpsocketserver.SendMsg(clientid,packtype,message) -} - -func (slf *TcpSocketPbService) Close(clientid uint64) error{ - return slf.tcpsocketserver.Close(clientid) -} - -func (slf *TcpSocketPbService) Send(clientid uint64,pack *network.MsgBasePack) error { - return slf.tcpsocketserver.Send(clientid,pack) -} diff --git a/sysservice/wsagentservice.go b/sysservice/wsagentservice.go deleted file mode 100644 index 08666f6..0000000 --- a/sysservice/wsagentservice.go +++ /dev/null @@ -1,41 +0,0 @@ -package sysservice - -import ( - "github.com/duanhf2012/origin/network" - "github.com/duanhf2012/origin/service" -) - -type WSAgentService struct { - service.BaseService - agentserver network.WSAgentServer - pattern string - port uint16 - bEnableCompression bool -} - -func (ws *WSAgentService) OnInit() error { - ws.AddModule(&ws.agentserver) - ws.agentserver.Init(ws.port) - return nil -} - -func (ws *WSAgentService) OnRun() bool { - ws.agentserver.Start() - - return false -} - -func NewWSAgentService(port uint16) *WSAgentService { - wss := new(WSAgentService) - - wss.port = port - return wss -} - -func (ws *WSAgentService) OnDestory() error { - return nil -} - -func (ws *WSAgentService) SetupAgent(pattern string, agent network.IAgent, bEnableCompression bool) { - ws.agentserver.SetupAgent(pattern, agent, bEnableCompression) -} diff --git a/sysservice/wsserverservice.go b/sysservice/wsserverservice.go deleted file mode 100644 index faabf7d..0000000 --- a/sysservice/wsserverservice.go +++ /dev/null @@ -1,47 +0,0 @@ -package sysservice - -import ( - "github.com/duanhf2012/origin/network" - "github.com/duanhf2012/origin/service" -) - -type WSServerService struct { - service.BaseService - wsserver network.WebsocketServer - - pattern string - port uint16 - messageReciver network.IMessageReceiver - bEnableCompression bool - } - -func (ws *WSServerService) OnInit() error { - - ws.wsserver.Init(ws.port) - return nil -} - -func (ws *WSServerService) OnRun() bool { - ws.wsserver.Start() - - return false -} - -func NewWSServerService(port uint16) *WSServerService { - wss := new(WSServerService) - - wss.port = port - return wss -} - -func (ws *WSServerService) OnDestory() error { - return nil -} -func (ws *WSServerService) SetupReciver(pattern string, messageReciver network.IMessageReceiver, bEnableCompression bool) { - ws.wsserver.SetupReciver(pattern, messageReciver, bEnableCompression) -} - -func (slf *WSServerService) SetWSS(certfile string, keyfile string) bool { - slf.wsserver.SetWSS(certfile, keyfile) - return true -} diff --git a/sysservice/wsservice.go b/sysservice/wsservice.go new file mode 100644 index 0000000..ce47f20 --- /dev/null +++ b/sysservice/wsservice.go @@ -0,0 +1,4 @@ +package sysservice + + + diff --git a/util/Log.go b/util/Log.go deleted file mode 100644 index 197d55d..0000000 --- a/util/Log.go +++ /dev/null @@ -1,10 +0,0 @@ -package util - - - -type PrintLog func(uint, string, ...interface{}) - -var Log PrintLog - - - diff --git a/util/Timer.go b/util/Timer.go deleted file mode 100644 index cc9c508..0000000 --- a/util/Timer.go +++ /dev/null @@ -1,94 +0,0 @@ -package util - -import "time" - -type Timer struct { - lasttime int64 - timeinterval int64 - - setupZeroDBase time.Duration //0表示普通模式 1表示切换分钟模式 -} - -func (slf *Timer) GetTimerinterval() int64 { - return slf.timeinterval -} - -func (slf *Timer) SetupTimer(ms int32) { - slf.lasttime = time.Now().UnixNano() - slf.timeinterval = int64(ms) * 1e6 -} - -func (slf *Timer) SetupTimerEx(tm time.Duration) { - slf.lasttime = time.Now().UnixNano() - slf.timeinterval = int64(tm) -} - - -func (slf *Timer) SetupTimerDouble() { - slf.lasttime = time.Now().UnixNano() - slf.timeinterval *= 2 -} - -func (slf *Timer) SetTimerHalf() { - slf.lasttime = time.Now().UnixNano() - slf.timeinterval /= 2 -} - -//检查整点分钟数触发 -func (slf *Timer) SetupZeroTimer(baseD time.Duration, interval int64) { - timeNow := time.Now() - nt := timeNow.Truncate(baseD) - slf.lasttime = nt.UnixNano() - slf.timeinterval = baseD.Nanoseconds() * interval - slf.setupZeroDBase = baseD -} - -func (slf *Timer) ResetStartTime() { - slf.lasttime = 0 -} - -func (slf *Timer) CheckTimeOut() bool { - now := time.Now() - if slf.setupZeroDBase.Nanoseconds() == 0 { - if now.UnixNano() > slf.lasttime+slf.timeinterval { - slf.lasttime = now.UnixNano() - return true - } - } else { //整点模式 - if now.UnixNano() > slf.lasttime+slf.timeinterval { - slf.SetupZeroTimer(slf.setupZeroDBase, slf.timeinterval/slf.setupZeroDBase.Nanoseconds()) - return true - } - } - - return false -} - -func GetTomorrowTimestamp() int64{ - timeStr := time.Now().Format("2006-01-02") - t, _ := time.ParseInLocation("2006-01-02 15:04:05", timeStr+" 23:59:59", time.Local) - return t.Unix()+1 -} - -func IsSameDay(timeFir, timeSec int64) bool{ - firTime:=time.Unix(timeFir,0) - secTime:=time.Unix(timeSec,0) - if firTime.Day()==secTime.Day()&&firTime.Month()==secTime.Month()&&firTime.Year()==secTime.Year(){ - return true - } - - return false -} - -func IsCrossOneDay(timeFir,timeSec int64)bool{ - firTime := time.Unix(timeFir,0) - secTime := time.Unix(timeSec,0) - firTime.Add(time.Hour*24).Day() - - if firTime.Day() == secTime.Day() && - firTime.Month()==secTime.Month()&& - firTime.Year()==secTime.Year(){ - return true - } - return false -} diff --git a/util/aes_encrypt.go b/util/aesencrypt/aes_encrypt.go similarity index 72% rename from util/aes_encrypt.go rename to util/aesencrypt/aes_encrypt.go index 7c34ca3..d42437e 100644 --- a/util/aes_encrypt.go +++ b/util/aesencrypt/aes_encrypt.go @@ -1,17 +1,4 @@ -// Copyright 2014 mqantserver Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package util +package aesencrypt import ( "crypto/aes" @@ -86,4 +73,4 @@ func (this *AesEncrypt) Decrypt(src []byte) (strDesc string, err error) { aesDecrypter := cipher.NewCFBDecrypter(aesBlockDecrypter, iv) aesDecrypter.XORKeyStream(decrypted, src) return string(decrypted), nil -} +} \ No newline at end of file diff --git a/util/Coroutine.go b/util/coroutine/coroutine.go similarity index 89% rename from util/Coroutine.go rename to util/coroutine/coroutine.go index 92d6dc7..bb99974 100644 --- a/util/Coroutine.go +++ b/util/coroutine/coroutine.go @@ -1,4 +1,4 @@ -package util +package coroutine import ( "fmt" @@ -12,11 +12,7 @@ func F(callback interface{},recoverNum int, args ...interface{}) { var coreInfo string coreInfo = string(debug.Stack()) coreInfo += "\n" + fmt.Sprintf("Core information is %v\n", r) - if Log != nil { - Log(5, coreInfo) - } else { - fmt.Print(coreInfo) - } + fmt.Print(coreInfo) if recoverNum==-1 ||recoverNum-1 >= 0 { recoverNum -= 1 diff --git a/util/deepcopy.go b/util/deepcopy/deepcopy.go similarity index 95% rename from util/deepcopy.go rename to util/deepcopy/deepcopy.go index 570718a..0d1dda1 100644 --- a/util/deepcopy.go +++ b/util/deepcopy/deepcopy.go @@ -1,9 +1,6 @@ -package util +package deepcopy -// reference: https://github.com/mohae/deepcopy -import ( - "reflect" -) +import "reflect" func deepCopy(dst, src reflect.Value) { switch src.Kind() { diff --git a/util/example_test.go b/util/example_test.go deleted file mode 100644 index e233ba3..0000000 --- a/util/example_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package util_test - -import ( - "fmt" - "testing" - - "github.com/duanhf2012/origin/util" -) - -func ExampleMap(t *testing.T) { - maps := util.NewMapEx() - for i := 0; i < 10000; i++ { - maps.Set(i, i) - } - - for i := 0; i < 10000; i++ { - ret := maps.Get(i) - if ret.(int) != i { - fmt.Printf("cannot find i:%d\n", i) - } - } - - for i := 0; i < 10000; i++ { - maps.LockSet(i, func(key interface{}, val interface{}) interface{} { - return val.(int) + 1 - }) - } - - for i := 0; i < 10000; i++ { - ret := maps.Get(i) - if ret.(int) != i { - fmt.Printf("cannot find i:%d\n", i) - } - } -} diff --git a/util/has/hash.go b/util/has/hash.go new file mode 100644 index 0000000..1ff3915 --- /dev/null +++ b/util/has/hash.go @@ -0,0 +1 @@ +package has diff --git a/util/hash/hash.go b/util/hash/hash.go index 54320be..4dea1b2 100644 --- a/util/hash/hash.go +++ b/util/hash/hash.go @@ -4,4 +4,4 @@ import "hash/crc32" func HashNumber(s string) uint { return uint(crc32.ChecksumIEEE([]byte(s))) -} +} \ No newline at end of file diff --git a/util/queue.go b/util/queue.go deleted file mode 100644 index ff2c667..0000000 --- a/util/queue.go +++ /dev/null @@ -1,101 +0,0 @@ -/* -Package queue provides a fast, ring-buffer queue based on the version suggested by Dariusz Górecki. -Using this instead of other, simpler, queue implementations (slice+append or linked list) provides -substantial memory and time benefits, and fewer GC pauses. -The queue implemented here is as fast as it is for an additional reason: it is *not* thread-safe. -*/ -package util - -// minQueueLen is smallest capacity that queue may have. -// Must be power of 2 for bitwise modulus: x % n == x & (n - 1). -const minQueueLen = 16 - -// Queue represents a single instance of the queue data structure. -type Queue struct { - buf []interface{} - head, tail, count int -} - -// New constructs and returns a new Queue. -func NewQueue() *Queue { - return &Queue{ - buf: make([]interface{}, minQueueLen), - } -} - -// Length returns the number of elements currently stored in the queue. -func (q *Queue) Length() int { - return q.count -} - -// resizes the queue to fit exactly twice its current contents -// this can result in shrinking if the queue is less than half-full -func (q *Queue) resize() { - newBuf := make([]interface{}, q.count<<1) - - if q.tail > q.head { - copy(newBuf, q.buf[q.head:q.tail]) - } else { - n := copy(newBuf, q.buf[q.head:]) - copy(newBuf[n:], q.buf[:q.tail]) - } - - q.head = 0 - q.tail = q.count - q.buf = newBuf -} - -// Add puts an element on the end of the queue. -func (q *Queue) Add(elem interface{}) { - if q.count == len(q.buf) { - q.resize() - } - - q.buf[q.tail] = elem - // bitwise modulus - q.tail = (q.tail + 1) & (len(q.buf) - 1) - q.count++ -} - -// Peek returns the element at the head of the queue. This call panics -// if the queue is empty. -func (q *Queue) Peek() interface{} { - if q.count <= 0 { - panic("queue: Peek() called on empty queue") - } - return q.buf[q.head] -} - -// Get returns the element at index i in the queue. If the index is -// invalid, the call will panic. This method accepts both positive and -// negative index values. Index 0 refers to the first element, and -// index -1 refers to the last. -func (q *Queue) Get(i int) interface{} { - // If indexing backwards, convert to positive index. - if i < 0 { - i += q.count - } - if i < 0 || i >= q.count { - panic("queue: Get() called with index out of range") - } - // bitwise modulus - return q.buf[(q.head+i)&(len(q.buf)-1)] -} - -// Remove removes and returns the element from the front of the queue. If the -// queue is empty, the call will panic. -func (q *Queue) Remove() interface{} { - if q.count <= 0 { - panic("queue: Remove() called on empty queue") - } - ret := q.buf[q.head] - q.buf[q.head] = nil - // bitwise modulus - q.head = (q.head + 1) & (len(q.buf) - 1) - q.count-- - // Resize down if buffer 1/4 full. - if len(q.buf) > minQueueLen && (q.count<<2) == len(q.buf) { - q.resize() - } - return ret -} diff --git a/util/queue/.gitignore b/util/queue/.gitignore deleted file mode 100644 index 8365624..0000000 --- a/util/queue/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe -*.test diff --git a/util/queue/.travis.yml b/util/queue/.travis.yml deleted file mode 100644 index 235a40a..0000000 --- a/util/queue/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: go -sudo: false - -go: - - 1.2 - - 1.3 - - 1.4 diff --git a/util/queue/LICENSE b/util/queue/LICENSE deleted file mode 100644 index d5f36db..0000000 --- a/util/queue/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Evan Huus - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/util/queue/README.md b/util/queue/README.md deleted file mode 100644 index db93693..0000000 --- a/util/queue/README.md +++ /dev/null @@ -1,16 +0,0 @@ -Queue -===== - -[](https://travis-ci.org/eapache/queue) -[](https://godoc.org/github.com/eapache/queue) -[](https://eapache.github.io/conduct.html) - -A fast Golang queue using a ring-buffer, based on the version suggested by Dariusz Górecki. -Using this instead of other, simpler, queue implementations (slice+append or linked list) provides -substantial memory and time benefits, and fewer GC pauses. - -The queue implemented here is as fast as it is in part because it is *not* thread-safe. - -Follows semantic versioning using https://gopkg.in/ - import from -[`gopkg.in/eapache/queue.v1`](https://gopkg.in/eapache/queue.v1) -for guaranteed API stability. diff --git a/util/rand.go b/util/rand/rand.go similarity index 98% rename from util/rand.go rename to util/rand/rand.go index 557c471..ad98c49 100644 --- a/util/rand.go +++ b/util/rand/rand.go @@ -1,4 +1,4 @@ -package util +package rand import ( "math/rand" diff --git a/util/semaphore.go b/util/semaphore/semaphore.go similarity index 91% rename from util/semaphore.go rename to util/semaphore/semaphore.go index 16fd136..00f5e85 100644 --- a/util/semaphore.go +++ b/util/semaphore/semaphore.go @@ -1,4 +1,4 @@ -package util +package semaphore type Semaphore chan struct{} diff --git a/util/sync_queue.go b/util/sync_queue.go deleted file mode 100644 index 186d464..0000000 --- a/util/sync_queue.go +++ /dev/null @@ -1,102 +0,0 @@ -package util - -import ( - "sync" -) - -// Synchronous FIFO queue -type SyncQueue struct { - lock sync.Mutex - popable *sync.Cond - buffer *Queue - closed bool -} - -// Create a new SyncQueue -func NewSyncQueue() *SyncQueue { - ch := &SyncQueue{ - buffer: NewQueue(), - } - ch.popable = sync.NewCond(&ch.lock) - return ch -} - -// Pop an item from SyncQueue, will block if SyncQueue is empty -func (q *SyncQueue) Pop() (v interface{}) { - c := q.popable - buffer := q.buffer - - q.lock.Lock() - for buffer.Length() == 0 && !q.closed { - c.Wait() - } - - if buffer.Length() > 0 { - v = buffer.Peek() - buffer.Remove() - } - - q.lock.Unlock() - return -} - -// Try to pop an item from SyncQueue, will return immediately with bool=false if SyncQueue is empty -func (q *SyncQueue) TryPop() (v interface{}, ok bool) { - buffer := q.buffer - - q.lock.Lock() - - if buffer.Length() > 0 { - v = buffer.Peek() - buffer.Remove() - ok = true - } else if q.closed { - ok = true - } - - q.lock.Unlock() - return -} - -// Push an item to SyncQueue. Always returns immediately without blocking -func (q *SyncQueue) Push(v interface{}) { - q.lock.Lock() - if !q.closed { - q.buffer.Add(v) - q.popable.Signal() - } - q.lock.Unlock() -} - -// Get the length of SyncQueue -func (q *SyncQueue) Len() (l int) { - q.lock.Lock() - l = q.buffer.Length() - q.lock.Unlock() - return -} - -// Close SyncQueue -// -// After close, Pop will return nil without block, and TryPop will return v=nil, ok=True -func (q *SyncQueue) Close() { - q.lock.Lock() - if !q.closed { - q.closed = true - q.popable.Signal() - } - q.lock.Unlock() -} - -func (q *SyncQueue) IsClose() (v bool) { - q.lock.Lock() - v = q.closed - q.lock.Unlock() - return -} - -func (q *SyncQueue) Get(i int) interface{} { - q.lock.Lock() - defer q.lock.Unlock() - return q.buffer.Get(i) -} diff --git a/util/timer/cronexpr.go b/util/timer/cronexpr.go new file mode 100644 index 0000000..694f0b4 --- /dev/null +++ b/util/timer/cronexpr.go @@ -0,0 +1,268 @@ +package timer + +// reference: https://github.com/robfig/cron +import ( + "fmt" + "math" + "strconv" + "strings" + "time" +) + +// Field name | Mandatory? | Allowed values | Allowed special characters +// ---------- | ---------- | -------------- | -------------------------- +// Seconds | No | 0-59 | * / , - +// Minutes | Yes | 0-59 | * / , - +// Hours | Yes | 0-23 | * / , - +// Day of month | Yes | 1-31 | * / , - +// Month | Yes | 1-12 | * / , - +// Day of week | Yes | 0-6 | * / , - +type CronExpr struct { + sec uint64 + min uint64 + hour uint64 + dom uint64 + month uint64 + dow uint64 +} + +// goroutine safe +func NewCronExpr(expr string) (cronExpr *CronExpr, err error) { + fields := strings.Fields(expr) + if len(fields) != 5 && len(fields) != 6 { + err = fmt.Errorf("invalid expr %v: expected 5 or 6 fields, got %v", expr, len(fields)) + return + } + + if len(fields) == 5 { + fields = append([]string{"0"}, fields...) + } + + cronExpr = new(CronExpr) + // Seconds + cronExpr.sec, err = parseCronField(fields[0], 0, 59) + if err != nil { + goto onError + } + // Minutes + cronExpr.min, err = parseCronField(fields[1], 0, 59) + if err != nil { + goto onError + } + // Hours + cronExpr.hour, err = parseCronField(fields[2], 0, 23) + if err != nil { + goto onError + } + // Day of month + cronExpr.dom, err = parseCronField(fields[3], 1, 31) + if err != nil { + goto onError + } + // Month + cronExpr.month, err = parseCronField(fields[4], 1, 12) + if err != nil { + goto onError + } + // Day of week + cronExpr.dow, err = parseCronField(fields[5], 0, 6) + if err != nil { + goto onError + } + return + +onError: + err = fmt.Errorf("invalid expr %v: %v", expr, err) + return +} + +// 1. * +// 2. num +// 3. num-num +// 4. */num +// 5. num/num (means num-max/num) +// 6. num-num/num +func parseCronField(field string, min int, max int) (cronField uint64, err error) { + fields := strings.Split(field, ",") + for _, field := range fields { + rangeAndIncr := strings.Split(field, "/") + if len(rangeAndIncr) > 2 { + err = fmt.Errorf("too many slashes: %v", field) + return + } + + // range + startAndEnd := strings.Split(rangeAndIncr[0], "-") + if len(startAndEnd) > 2 { + err = fmt.Errorf("too many hyphens: %v", rangeAndIncr[0]) + return + } + + var start, end int + if startAndEnd[0] == "*" { + if len(startAndEnd) != 1 { + err = fmt.Errorf("invalid range: %v", rangeAndIncr[0]) + return + } + start = min + end = max + } else { + // start + start, err = strconv.Atoi(startAndEnd[0]) + if err != nil { + err = fmt.Errorf("invalid range: %v", rangeAndIncr[0]) + return + } + // end + if len(startAndEnd) == 1 { + if len(rangeAndIncr) == 2 { + end = max + } else { + end = start + } + } else { + end, err = strconv.Atoi(startAndEnd[1]) + if err != nil { + err = fmt.Errorf("invalid range: %v", rangeAndIncr[0]) + return + } + } + } + + if start > end { + err = fmt.Errorf("invalid range: %v", rangeAndIncr[0]) + return + } + if start < min { + err = fmt.Errorf("out of range [%v, %v]: %v", min, max, rangeAndIncr[0]) + return + } + if end > max { + err = fmt.Errorf("out of range [%v, %v]: %v", min, max, rangeAndIncr[0]) + return + } + + // increment + var incr int + if len(rangeAndIncr) == 1 { + incr = 1 + } else { + incr, err = strconv.Atoi(rangeAndIncr[1]) + if err != nil { + err = fmt.Errorf("invalid increment: %v", rangeAndIncr[1]) + return + } + if incr <= 0 { + err = fmt.Errorf("invalid increment: %v", rangeAndIncr[1]) + return + } + } + + // cronField + if incr == 1 { + cronField |= ^(math.MaxUint64 << uint(end+1)) & (math.MaxUint64 << uint(start)) + } else { + for i := start; i <= end; i += incr { + cronField |= 1 << uint(i) + } + } + } + + return +} + +func (e *CronExpr) matchDay(t time.Time) bool { + // day-of-month blank + if e.dom == 0xfffffffe { + return 1< year+1 { + return time.Time{} + } + + // Month + for 1< 0 { + buf := make([]byte, conf.LenStackBuf) + l := runtime.Stack(buf, false) + log.Error("%v: %s", r, buf[:l]) + } else { + log.Error("%v", r) + } + } + }() + */ + + if t.cbex!=nil { + t.cbex(t) + }else{ + t.cb() + } + +} + +func (disp *Dispatcher) AfterFunc(d time.Duration, cb func()) *Timer { + t := new(Timer) + t.cb = cb + t.t = time.AfterFunc(d, func() { + disp.ChanTimer <- t + }) + return t +} + +func (disp *Dispatcher) AfterFuncEx(d time.Duration, cbex func(timer *Timer)) *Timer { + t := new(Timer) + t.cbex = cbex + t.t = time.AfterFunc(d, func() { + disp.ChanTimer <- t + }) + return t +} + +// Cron +type Cron struct { + t *Timer +} + +func (c *Cron) Stop() { + if c.t != nil { + c.t.Stop() + } +} + +func (disp *Dispatcher) CronFunc(cronExpr *CronExpr, _cb func()) *Cron { + c := new(Cron) + + now := time.Now() + nextTime := cronExpr.Next(now) + if nextTime.IsZero() { + return c + } + + // callback + var cb func() + cb = func() { + defer _cb() + + now := time.Now() + nextTime := cronExpr.Next(now) + if nextTime.IsZero() { + return + } + c.t = disp.AfterFunc(nextTime.Sub(now), cb) + } + + c.t = disp.AfterFunc(nextTime.Sub(now), cb) + return c +} + + +func (disp *Dispatcher) CronFuncEx(cronExpr *CronExpr, _cb func(*Cron)) *Cron { + c := new(Cron) + + now := time.Now() + nextTime := cronExpr.Next(now) + if nextTime.IsZero() { + return c + } + + // callback + var cb func() + cb = func() { + defer _cb(c) + + now := time.Now() + nextTime := cronExpr.Next(now) + if nextTime.IsZero() { + return + } + c.t = disp.AfterFunc(nextTime.Sub(now), cb) + } + + c.t = disp.AfterFunc(nextTime.Sub(now), cb) + return c +} \ No newline at end of file diff --git a/util/map.go b/util/umap/map.go similarity index 98% rename from util/map.go rename to util/umap/map.go index 50d7bfc..a6937e6 100644 --- a/util/map.go +++ b/util/umap/map.go @@ -1,8 +1,6 @@ -package util +package umap -import ( - "sync" -) +import "sync" type Map struct { sync.RWMutex diff --git a/util/mapex.go b/util/umap/mapEx.go similarity index 88% rename from util/mapex.go rename to util/umap/mapEx.go index 8c8bfc6..6dc6dc7 100644 --- a/util/mapex.go +++ b/util/umap/mapEx.go @@ -1,10 +1,9 @@ -package util +package umap import ( "fmt" - "github.com/duanhf2012/origin/util/hash" + "github.com/duanhf2012/originnet/util/hash" "sync" - "sync/atomic" ) const ( @@ -16,7 +15,6 @@ type MapEx struct { m []map[interface{}]interface{} l []sync.RWMutex hashMapNum int - rangeIdx uint32 } func (m *MapEx) Init(hashMapNum int) { @@ -37,19 +35,6 @@ func NewMapEx() *MapEx { return &mapEx } - -func (m *MapEx) NextRLockRange(f func(key interface{}, value interface{})) { - i := atomic.AddUint32(&m.rangeIdx,1)%uint32(m.hashMapNum) - - m.l[i].RLock() - for key, val := range m.m[i] { - f(key, val) - } - - m.l[i].RUnlock() -} - - func (m *MapEx) ClearMap() { for i := 0; i < DEFAULT_SAFE_MAP_MAX_HASH_NUM; i++ { m.l[i].Lock() @@ -64,7 +49,7 @@ func (m *MapEx) GetHashCode(key interface{}) int { func (m *MapEx) GetArrayIdByKey(key interface{}) int { if m.hashMapNum ==0 { - return -1 + return -1 } idx := m.GetHashCode(key) % m.hashMapNum if idx > m.hashMapNum { @@ -211,15 +196,9 @@ func (m *MapEx) LockSet(key interface{}, f func(value interface{}) interface{}) ret, ok := val[key] if ok == false { - ret := f(nil) - if ret != nil { - val[key] =ret - } + val[key] = f(nil) } else { - ret := f(ret) - if ret != nil { - val[key] =ret - } + val[key] = f(ret) } m.l[idx].Unlock() diff --git a/util/uuid/uuid.go b/util/uuid/uuid.go index 4666fb3..a4ef28d 100644 --- a/util/uuid/uuid.go +++ b/util/uuid/uuid.go @@ -1,16 +1,3 @@ -// Copyright 2014 mqant Author. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. package uuid import ( @@ -118,4 +105,4 @@ func randBytes(x []byte) { x[length] = byte(mrand.Int31n(256)) } } -} +} \ No newline at end of file