You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

message.py 211KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947
  1. ###############################################################################
  2. #
  3. # The MIT License (MIT)
  4. #
  5. # Copyright (c) Crossbar.io Technologies GmbH
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a copy
  8. # of this software and associated documentation files (the "Software"), to deal
  9. # in the Software without restriction, including without limitation the rights
  10. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. # copies of the Software, and to permit persons to whom the Software is
  12. # furnished to do so, subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice shall be included in
  15. # all copies or substantial portions of the Software.
  16. #
  17. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. # THE SOFTWARE.
  24. #
  25. ###############################################################################
  26. from __future__ import absolute_import
  27. import re
  28. import binascii
  29. import six
  30. import autobahn
  31. from autobahn.wamp.exception import ProtocolError, InvalidUriError
  32. from autobahn.wamp.role import ROLE_NAME_TO_CLASS
  33. try:
  34. import cbor
  35. import flatbuffers
  36. from autobahn.wamp import message_fbs
  37. except ImportError:
  38. _HAS_WAMP_FLATBUFFERS = False
  39. else:
  40. _HAS_WAMP_FLATBUFFERS = True
  41. __all__ = ('Message',
  42. 'Hello',
  43. 'Welcome',
  44. 'Abort',
  45. 'Challenge',
  46. 'Authenticate',
  47. 'Goodbye',
  48. 'Error',
  49. 'Publish',
  50. 'Published',
  51. 'Subscribe',
  52. 'Subscribed',
  53. 'Unsubscribe',
  54. 'Unsubscribed',
  55. 'Event',
  56. 'Call',
  57. 'Cancel',
  58. 'Result',
  59. 'Register',
  60. 'Registered',
  61. 'Unregister',
  62. 'Unregistered',
  63. 'Invocation',
  64. 'Interrupt',
  65. 'Yield',
  66. 'check_or_raise_uri',
  67. 'check_or_raise_id',
  68. 'is_valid_enc_algo',
  69. 'is_valid_enc_serializer',
  70. 'PAYLOAD_ENC_CRYPTO_BOX',
  71. 'PAYLOAD_ENC_MQTT',
  72. 'PAYLOAD_ENC_STANDARD_IDENTIFIERS')
  73. # strict URI check allowing empty URI components
  74. _URI_PAT_STRICT_EMPTY = re.compile(r"^(([0-9a-z_]+\.)|\.)*([0-9a-z_]+)?$")
  75. # loose URI check allowing empty URI components
  76. _URI_PAT_LOOSE_EMPTY = re.compile(r"^(([^\s\.#]+\.)|\.)*([^\s\.#]+)?$")
  77. # strict URI check disallowing empty URI components
  78. _URI_PAT_STRICT_NON_EMPTY = re.compile(r"^([0-9a-z_]+\.)*([0-9a-z_]+)$")
  79. # loose URI check disallowing empty URI components
  80. _URI_PAT_LOOSE_NON_EMPTY = re.compile(r"^([^\s\.#]+\.)*([^\s\.#]+)$")
  81. # strict URI check disallowing empty URI components in all but the last component
  82. _URI_PAT_STRICT_LAST_EMPTY = re.compile(r"^([0-9a-z_]+\.)*([0-9a-z_]*)$")
  83. # loose URI check disallowing empty URI components in all but the last component
  84. _URI_PAT_LOOSE_LAST_EMPTY = re.compile(r"^([^\s\.#]+\.)*([^\s\.#]*)$")
  85. # custom (=implementation specific) WAMP attributes (used in WAMP message details/options)
  86. _CUSTOM_ATTRIBUTE = re.compile(r"^x_([a-z][0-9a-z_]+)?$")
  87. # Value for algo attribute in end-to-end encrypted messages using cryptobox, which
  88. # is a scheme based on Curve25519, SHA512, Salsa20 and Poly1305.
  89. # See: http://cr.yp.to/highspeed/coolnacl-20120725.pdf
  90. PAYLOAD_ENC_CRYPTO_BOX = u'cryptobox'
  91. # Payload transparency identifier for MQTT payloads (which are arbitrary binary).
  92. PAYLOAD_ENC_MQTT = u'mqtt'
  93. # Payload transparency identifier for XBR payloads
  94. PAYLOAD_ENC_XBR = u'xbr'
  95. # Payload transparency algorithm identifiers from the WAMP spec.
  96. PAYLOAD_ENC_STANDARD_IDENTIFIERS = [PAYLOAD_ENC_CRYPTO_BOX, PAYLOAD_ENC_MQTT, PAYLOAD_ENC_XBR]
  97. # Payload transparency serializer identifiers from the WAMP spec.
  98. PAYLOAD_ENC_STANDARD_SERIALIZERS = [u'json', u'msgpack', u'cbor', u'ubjson', u'flatbuffers']
  99. ENC_ALGO_NONE = 0
  100. ENC_ALGO_CRYPTOBOX = 1
  101. ENC_ALGO_MQTT = 2
  102. ENC_ALGO_XBR = 3
  103. ENC_ALGOS = {
  104. ENC_ALGO_NONE: u'null',
  105. ENC_ALGO_CRYPTOBOX: u'cryptobox',
  106. ENC_ALGO_MQTT: u'mqtt',
  107. ENC_ALGO_XBR: u'xbr',
  108. }
  109. ENC_ALGOS_FROMSTR = {key: value for value, key in ENC_ALGOS.items()}
  110. ENC_SER_NONE = 0
  111. ENC_SER_JSON = 1
  112. ENC_SER_MSGPACK = 2
  113. ENC_SER_CBOR = 3
  114. ENC_SER_UBJSON = 4
  115. ENC_SER_OPAQUE = 5
  116. ENC_SER_FLATBUFFERS = 6
  117. ENC_SERS = {
  118. ENC_SER_NONE: u'null',
  119. ENC_SER_JSON: u'json',
  120. ENC_SER_MSGPACK: u'msgpack',
  121. ENC_SER_CBOR: u'cbor',
  122. ENC_SER_UBJSON: u'ubjson',
  123. ENC_SER_OPAQUE: u'opaque',
  124. ENC_SER_FLATBUFFERS: u'flatbuffers',
  125. }
  126. ENC_SERS_FROMSTR = {key: value for value, key in ENC_SERS.items()}
  127. def is_valid_enc_algo(enc_algo):
  128. """
  129. For WAMP payload transparency mode, check if the provided ``enc_algo``
  130. identifier in the WAMP message is a valid one.
  131. Currently defined standard identifiers are:
  132. * ``"cryptobox"``
  133. * ``"mqtt"``
  134. * ``"xbr"``
  135. Users can select arbitrary identifiers too, but these MUST start with ``u"x_"``.
  136. :param enc_algo: The payload transparency algorithm identifier to check.
  137. :type enc_algo: str
  138. :returns: Returns ``True`` if and only if the payload transparency
  139. algorithm identifier is valid.
  140. :rtype: bool
  141. """
  142. return type(enc_algo) == six.text_type and (enc_algo in PAYLOAD_ENC_STANDARD_IDENTIFIERS or _CUSTOM_ATTRIBUTE.match(enc_algo))
  143. def is_valid_enc_serializer(enc_serializer):
  144. """
  145. For WAMP payload transparency mode, check if the provided ``enc_serializer``
  146. identifier in the WAMP message is a valid one.
  147. Currently, the only standard defined identifier are
  148. * ``"json"``
  149. * ``"msgpack"``
  150. * ``"cbor"``
  151. * ``"ubjson"``
  152. * ``"flatbuffers"``
  153. Users can select arbitrary identifiers too, but these MUST start with ``u"x_"``.
  154. :param enc_serializer: The payload transparency serializer identifier to check.
  155. :type enc_serializer: str
  156. :returns: Returns ``True`` if and only if the payload transparency
  157. serializer identifier is valid.
  158. :rtype: bool
  159. """
  160. return type(enc_serializer) == six.text_type and (enc_serializer in PAYLOAD_ENC_STANDARD_SERIALIZERS or _CUSTOM_ATTRIBUTE.match(enc_serializer))
  161. def b2a(data, max_len=40):
  162. if type(data) == six.text_type:
  163. s = data
  164. elif type(data) == six.binary_type:
  165. s = binascii.b2a_hex(data).decode('ascii')
  166. elif data is None:
  167. s = u'-'
  168. else:
  169. s = u'{}'.format(data)
  170. if len(s) > max_len:
  171. return s[:max_len] + u'..'
  172. else:
  173. return s
  174. def check_or_raise_uri(value, message=u"WAMP message invalid", strict=False, allow_empty_components=False, allow_last_empty=False, allow_none=False):
  175. """
  176. Check a value for being a valid WAMP URI.
  177. If the value is not a valid WAMP URI is invalid, raises :class:`autobahn.wamp.exception.ProtocolError`.
  178. Otherwise return the value.
  179. :param value: The value to check.
  180. :type value: str or None
  181. :param message: Prefix for message in exception raised when value is invalid.
  182. :type message: str
  183. :param strict: If ``True``, do a strict check on the URI (the WAMP spec SHOULD behavior).
  184. :type strict: bool
  185. :param allow_empty_components: If ``True``, allow empty URI components (for pattern based
  186. subscriptions and registrations).
  187. :type allow_empty_components: bool
  188. :param allow_none: If ``True``, allow ``None`` for URIs.
  189. :type allow_none: bool
  190. :returns: The URI value (if valid).
  191. :rtype: str
  192. :raises: instance of :class:`autobahn.wamp.exception.ProtocolError`
  193. """
  194. if value is None:
  195. if allow_none:
  196. return
  197. else:
  198. raise InvalidUriError(u"{0}: URI cannot be null".format(message))
  199. if type(value) != six.text_type:
  200. if not (value is None and allow_none):
  201. raise InvalidUriError(u"{0}: invalid type {1} for URI".format(message, type(value)))
  202. if strict:
  203. if allow_last_empty:
  204. pat = _URI_PAT_STRICT_LAST_EMPTY
  205. elif allow_empty_components:
  206. pat = _URI_PAT_STRICT_EMPTY
  207. else:
  208. pat = _URI_PAT_STRICT_NON_EMPTY
  209. else:
  210. if allow_last_empty:
  211. pat = _URI_PAT_LOOSE_LAST_EMPTY
  212. elif allow_empty_components:
  213. pat = _URI_PAT_LOOSE_EMPTY
  214. else:
  215. pat = _URI_PAT_LOOSE_NON_EMPTY
  216. if not pat.match(value):
  217. raise InvalidUriError(u'{0}: invalid value "{1}" for URI (did not match pattern "{2}" with options strict={3}, allow_empty_components={4}, allow_last_empty={5}, allow_none={6})'.format(message, value, pat.pattern, strict, allow_empty_components, allow_last_empty, allow_none))
  218. else:
  219. return value
  220. def check_or_raise_id(value, message=u"WAMP message invalid"):
  221. """
  222. Check a value for being a valid WAMP ID.
  223. If the value is not a valid WAMP ID, raises :class:`autobahn.wamp.exception.ProtocolError`.
  224. Otherwise return the value.
  225. :param value: The value to check.
  226. :type value: int
  227. :param message: Prefix for message in exception raised when value is invalid.
  228. :type message: str
  229. :returns: The ID value (if valid).
  230. :rtype: int
  231. :raises: instance of :class:`autobahn.wamp.exception.ProtocolError`
  232. """
  233. if type(value) not in six.integer_types:
  234. raise ProtocolError(u"{0}: invalid type {1} for ID".format(message, type(value)))
  235. # the value 0 for WAMP IDs is possible in certain WAMP messages, e.g. UNREGISTERED with
  236. # router revocation signaling!
  237. if value < 0 or value > 9007199254740992: # 2**53
  238. raise ProtocolError(u"{0}: invalid value {1} for ID".format(message, value))
  239. return value
  240. def check_or_raise_extra(value, message=u"WAMP message invalid"):
  241. """
  242. Check a value for being a valid WAMP extra dictionary.
  243. If the value is not a valid WAMP extra dictionary, raises :class:`autobahn.wamp.exception.ProtocolError`.
  244. Otherwise return the value.
  245. :param value: The value to check.
  246. :type value: dict
  247. :param message: Prefix for message in exception raised when value is invalid.
  248. :type message: str
  249. :returns: The extra dictionary (if valid).
  250. :rtype: dict
  251. :raises: instance of :class:`autobahn.wamp.exception.ProtocolError`
  252. """
  253. if type(value) != dict:
  254. raise ProtocolError(u"{0}: invalid type {1} for WAMP extra".format(message, type(value)))
  255. for k in value.keys():
  256. if not isinstance(k, six.text_type):
  257. raise ProtocolError(u"{0}: invalid type {1} for key in WAMP extra ('{2}')".format(message, type(k), k))
  258. return value
  259. def _validate_kwargs(kwargs, message=u"WAMP message invalid"):
  260. """
  261. Check a value for being a valid WAMP kwargs dictionary.
  262. If the value is not a valid WAMP kwargs dictionary,
  263. raises :class:`autobahn.wamp.exception.ProtocolError`.
  264. Otherwise return the kwargs.
  265. The WAMP spec requires that the keys in kwargs are proper
  266. strings (unicode), not bytes. Note that the WAMP spec
  267. says nothing about keys in application payload. Key in the
  268. latter can be potentially of other type (if that is really
  269. wanted).
  270. :param kwargs: The keyword arguments to check.
  271. :type kwargs: dict
  272. :param message: Prefix for message in exception raised when
  273. value is invalid.
  274. :type message: str
  275. :returns: The kwargs dictionary (if valid).
  276. :rtype: dict
  277. :raises: instance of
  278. :class:`autobahn.wamp.exception.ProtocolError`
  279. """
  280. if kwargs is not None:
  281. if type(kwargs) != dict:
  282. raise ProtocolError(u"{0}: invalid type {1} for WAMP kwargs".format(message, type(kwargs)))
  283. for k in kwargs.keys():
  284. if not isinstance(k, six.text_type):
  285. raise ProtocolError(u"{0}: invalid type {1} for key in WAMP kwargs ('{2}')".format(message, type(k), k))
  286. return kwargs
  287. class Message(object):
  288. """
  289. WAMP message base class.
  290. .. note:: This is not supposed to be instantiated, but subclassed only.
  291. """
  292. MESSAGE_TYPE = None
  293. """
  294. WAMP message type code.
  295. """
  296. __slots__ = (
  297. '_from_fbs',
  298. '_serialized',
  299. '_correlation_id',
  300. '_correlation_uri',
  301. '_correlation_is_anchor',
  302. '_correlation_is_last',
  303. )
  304. def __init__(self, from_fbs=None):
  305. # only filled in case this object has flatbuffers underlying
  306. self._from_fbs = from_fbs
  307. # serialization cache: mapping from ISerializer instances to serialized bytes
  308. self._serialized = {}
  309. # user attributes for message correlation (mainly for message tracing)
  310. self._correlation_id = None
  311. self._correlation_uri = None
  312. self._correlation_is_anchor = None
  313. self._correlation_is_last = None
  314. @property
  315. def correlation_id(self):
  316. return self._correlation_id
  317. @correlation_id.setter
  318. def correlation_id(self, value):
  319. assert(value is None or type(value) == six.text_type)
  320. self._correlation_id = value
  321. @property
  322. def correlation_uri(self):
  323. return self._correlation_uri
  324. @correlation_uri.setter
  325. def correlation_uri(self, value):
  326. assert(value is None or type(value) == six.text_type)
  327. self._correlation_uri = value
  328. @property
  329. def correlation_is_anchor(self):
  330. return self._correlation_is_anchor
  331. @correlation_is_anchor.setter
  332. def correlation_is_anchor(self, value):
  333. assert(value is None or type(value) == bool)
  334. self._correlation_is_anchor = value
  335. @property
  336. def correlation_is_last(self):
  337. return self._correlation_is_last
  338. @correlation_is_last.setter
  339. def correlation_is_last(self, value):
  340. assert(value is None or type(value) == bool)
  341. self._correlation_is_last = value
  342. def __eq__(self, other):
  343. """
  344. Compare this message to another message for equality.
  345. :param other: The other message to compare with.
  346. :type other: obj
  347. :returns: ``True`` iff the messages are equal.
  348. :rtype: bool
  349. """
  350. if not isinstance(other, self.__class__):
  351. return False
  352. # we only want the actual message data attributes (not eg _serialize)
  353. for k in self.__slots__:
  354. if k not in ['_serialized',
  355. '_correlation_id',
  356. '_correlation_uri',
  357. '_correlation_is_anchor',
  358. '_correlation_is_last'] and not k.startswith('_'):
  359. if not getattr(self, k) == getattr(other, k):
  360. return False
  361. return True
  362. def __ne__(self, other):
  363. """
  364. Compare this message to another message for inequality.
  365. :param other: The other message to compare with.
  366. :type other: obj
  367. :returns: ``True`` iff the messages are not equal.
  368. :rtype: bool
  369. """
  370. return not self.__eq__(other)
  371. @staticmethod
  372. def parse(wmsg):
  373. """
  374. Factory method that parses a unserialized raw message (as returned byte
  375. :func:`autobahn.interfaces.ISerializer.unserialize`) into an instance
  376. of this class.
  377. :returns: An instance of this class.
  378. :rtype: obj
  379. """
  380. raise NotImplementedError()
  381. def marshal(self):
  382. raise NotImplementedError()
  383. @staticmethod
  384. def cast(buf):
  385. raise NotImplementedError()
  386. def build(self, builder):
  387. raise NotImplementedError()
  388. def uncache(self):
  389. """
  390. Resets the serialization cache.
  391. """
  392. self._serialized = {}
  393. def serialize(self, serializer):
  394. """
  395. Serialize this object into a wire level bytes representation and cache
  396. the resulting bytes. If the cache already contains an entry for the given
  397. serializer, return the cached representation directly.
  398. :param serializer: The wire level serializer to use.
  399. :type serializer: An instance that implements :class:`autobahn.interfaces.ISerializer`
  400. :returns: The serialized bytes.
  401. :rtype: bytes
  402. """
  403. # only serialize if not cached ..
  404. if serializer not in self._serialized:
  405. if serializer.NAME == u'flatbuffers':
  406. # flatbuffers get special treatment ..
  407. builder = flatbuffers.Builder(1024)
  408. # this is the core method writing out this message (self) to a (new) flatbuffer
  409. # FIXME: implement this method for all classes derived from Message
  410. obj = self.build(builder)
  411. builder.Finish(obj)
  412. buf = builder.Output()
  413. self._serialized[serializer] = bytes(buf)
  414. else:
  415. # all other serializers first marshal() the object and then serialize the latter
  416. self._serialized[serializer] = serializer.serialize(self.marshal())
  417. # cache is filled now: return serialized, cached bytes
  418. return self._serialized[serializer]
  419. class Hello(Message):
  420. """
  421. A WAMP ``HELLO`` message.
  422. Format: ``[HELLO, Realm|uri, Details|dict]``
  423. """
  424. MESSAGE_TYPE = 1
  425. """
  426. The WAMP message code for this type of message.
  427. """
  428. __slots__ = (
  429. 'realm',
  430. 'roles',
  431. 'authmethods',
  432. 'authid',
  433. 'authrole',
  434. 'authextra',
  435. 'resumable',
  436. 'resume_session',
  437. 'resume_token',
  438. )
  439. def __init__(self,
  440. realm,
  441. roles,
  442. authmethods=None,
  443. authid=None,
  444. authrole=None,
  445. authextra=None,
  446. resumable=None,
  447. resume_session=None,
  448. resume_token=None):
  449. """
  450. :param realm: The URI of the WAMP realm to join.
  451. :type realm: str
  452. :param roles: The WAMP session roles and features to announce.
  453. :type roles: dict of :class:`autobahn.wamp.role.RoleFeatures`
  454. :param authmethods: The authentication methods to announce.
  455. :type authmethods: list of str or None
  456. :param authid: The authentication ID to announce.
  457. :type authid: str or None
  458. :param authrole: The authentication role to announce.
  459. :type authrole: str or None
  460. :param authextra: Application-specific "extra data" to be forwarded to the client.
  461. :type authextra: dict or None
  462. :param resumable: Whether the client wants this to be a session that can be later resumed.
  463. :type resumable: bool or None
  464. :param resume_session: The session the client would like to resume.
  465. :type resume_session: int or None
  466. :param resume_token: The secure authorisation token to resume the session.
  467. :type resume_token: str or None
  468. """
  469. assert(realm is None or isinstance(realm, six.text_type))
  470. assert(type(roles) == dict)
  471. assert(len(roles) > 0)
  472. for role in roles:
  473. assert(role in [u'subscriber', u'publisher', u'caller', u'callee'])
  474. assert(isinstance(roles[role], autobahn.wamp.role.ROLE_NAME_TO_CLASS[role]))
  475. if authmethods:
  476. assert(type(authmethods) == list)
  477. for authmethod in authmethods:
  478. assert(type(authmethod) == six.text_type)
  479. assert(authid is None or type(authid) == six.text_type)
  480. assert(authrole is None or type(authrole) == six.text_type)
  481. assert(authextra is None or type(authextra) == dict)
  482. assert(resumable is None or type(resumable) == bool)
  483. assert(resume_session is None or type(resume_session) == int)
  484. assert(resume_token is None or type(resume_token) == six.text_type)
  485. Message.__init__(self)
  486. self.realm = realm
  487. self.roles = roles
  488. self.authmethods = authmethods
  489. self.authid = authid
  490. self.authrole = authrole
  491. self.authextra = authextra
  492. self.resumable = resumable
  493. self.resume_session = resume_session
  494. self.resume_token = resume_token
  495. @staticmethod
  496. def parse(wmsg):
  497. """
  498. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  499. :param wmsg: The unserialized raw message.
  500. :type wmsg: list
  501. :returns: An instance of this class.
  502. """
  503. # this should already be verified by WampSerializer.unserialize
  504. assert(len(wmsg) > 0 and wmsg[0] == Hello.MESSAGE_TYPE)
  505. if len(wmsg) != 3:
  506. raise ProtocolError("invalid message length {0} for HELLO".format(len(wmsg)))
  507. realm = check_or_raise_uri(wmsg[1], u"'realm' in HELLO", allow_none=True)
  508. details = check_or_raise_extra(wmsg[2], u"'details' in HELLO")
  509. roles = {}
  510. if u'roles' not in details:
  511. raise ProtocolError(u"missing mandatory roles attribute in options in HELLO")
  512. details_roles = check_or_raise_extra(details[u'roles'], u"'roles' in 'details' in HELLO")
  513. if len(details_roles) == 0:
  514. raise ProtocolError(u"empty 'roles' in 'details' in HELLO")
  515. for role in details_roles:
  516. if role not in [u'subscriber', u'publisher', u'caller', u'callee']:
  517. raise ProtocolError("invalid role '{0}' in 'roles' in 'details' in HELLO".format(role))
  518. role_cls = ROLE_NAME_TO_CLASS[role]
  519. details_role = check_or_raise_extra(details_roles[role], "role '{0}' in 'roles' in 'details' in HELLO".format(role))
  520. if u'features' in details_role:
  521. check_or_raise_extra(details_role[u'features'], "'features' in role '{0}' in 'roles' in 'details' in HELLO".format(role))
  522. role_features = role_cls(**details_role[u'features'])
  523. else:
  524. role_features = role_cls()
  525. roles[role] = role_features
  526. authmethods = None
  527. if u'authmethods' in details:
  528. details_authmethods = details[u'authmethods']
  529. if type(details_authmethods) != list:
  530. raise ProtocolError("invalid type {0} for 'authmethods' detail in HELLO".format(type(details_authmethods)))
  531. for auth_method in details_authmethods:
  532. if type(auth_method) != six.text_type:
  533. raise ProtocolError("invalid type {0} for item in 'authmethods' detail in HELLO".format(type(auth_method)))
  534. authmethods = details_authmethods
  535. authid = None
  536. if u'authid' in details:
  537. details_authid = details[u'authid']
  538. if type(details_authid) != six.text_type:
  539. raise ProtocolError("invalid type {0} for 'authid' detail in HELLO".format(type(details_authid)))
  540. authid = details_authid
  541. authrole = None
  542. if u'authrole' in details:
  543. details_authrole = details[u'authrole']
  544. if type(details_authrole) != six.text_type:
  545. raise ProtocolError("invalid type {0} for 'authrole' detail in HELLO".format(type(details_authrole)))
  546. authrole = details_authrole
  547. authextra = None
  548. if u'authextra' in details:
  549. details_authextra = details[u'authextra']
  550. if type(details_authextra) != dict:
  551. raise ProtocolError("invalid type {0} for 'authextra' detail in HELLO".format(type(details_authextra)))
  552. authextra = details_authextra
  553. resumable = None
  554. if u'resumable' in details:
  555. resumable = details[u'resumable']
  556. if type(resumable) != bool:
  557. raise ProtocolError("invalid type {0} for 'resumable' detail in HELLO".format(type(resumable)))
  558. resume_session = None
  559. if u'resume-session' in details:
  560. resume_session = details[u'resume-session']
  561. if type(resume_session) != int:
  562. raise ProtocolError("invalid type {0} for 'resume-session' detail in HELLO".format(type(resume_session)))
  563. resume_token = None
  564. if u'resume-token' in details:
  565. resume_token = details[u'resume-token']
  566. if type(resume_token) != six.text_type:
  567. raise ProtocolError("invalid type {0} for 'resume-token' detail in HELLO".format(type(resume_token)))
  568. else:
  569. if resume_session:
  570. raise ProtocolError("resume-token must be provided if resume-session is provided in HELLO")
  571. obj = Hello(realm, roles, authmethods, authid, authrole, authextra, resumable, resume_session, resume_token)
  572. return obj
  573. def marshal(self):
  574. """
  575. Marshal this object into a raw message for subsequent serialization to bytes.
  576. :returns: The serialized raw message.
  577. :rtype: list
  578. """
  579. details = {u'roles': {}}
  580. for role in self.roles.values():
  581. details[u'roles'][role.ROLE] = {}
  582. for feature in role.__dict__:
  583. if not feature.startswith('_') and feature != 'ROLE' and getattr(role, feature) is not None:
  584. if u'features' not in details[u'roles'][role.ROLE]:
  585. details[u'roles'][role.ROLE] = {u'features': {}}
  586. details[u'roles'][role.ROLE][u'features'][six.u(feature)] = getattr(role, feature)
  587. if self.authmethods is not None:
  588. details[u'authmethods'] = self.authmethods
  589. if self.authid is not None:
  590. details[u'authid'] = self.authid
  591. if self.authrole is not None:
  592. details[u'authrole'] = self.authrole
  593. if self.authextra is not None:
  594. details[u'authextra'] = self.authextra
  595. if self.resumable is not None:
  596. details[u'resumable'] = self.resumable
  597. if self.resume_session is not None:
  598. details[u'resume-session'] = self.resume_session
  599. if self.resume_token is not None:
  600. details[u'resume-token'] = self.resume_token
  601. return [Hello.MESSAGE_TYPE, self.realm, details]
  602. def __str__(self):
  603. """
  604. Return a string representation of this message.
  605. """
  606. return u"Hello(realm={}, roles={}, authmethods={}, authid={}, authrole={}, authextra={}, resumable={}, resume_session={}, resume_token={})".format(self.realm, self.roles, self.authmethods, self.authid, self.authrole, self.authextra, self.resumable, self.resume_session, self.resume_token)
  607. class Welcome(Message):
  608. """
  609. A WAMP ``WELCOME`` message.
  610. Format: ``[WELCOME, Session|id, Details|dict]``
  611. """
  612. MESSAGE_TYPE = 2
  613. """
  614. The WAMP message code for this type of message.
  615. """
  616. __slots__ = (
  617. 'session',
  618. 'roles',
  619. 'realm',
  620. 'authid',
  621. 'authrole',
  622. 'authmethod',
  623. 'authprovider',
  624. 'authextra',
  625. 'resumed',
  626. 'resumable',
  627. 'resume_token',
  628. 'custom',
  629. )
  630. def __init__(self,
  631. session,
  632. roles,
  633. realm=None,
  634. authid=None,
  635. authrole=None,
  636. authmethod=None,
  637. authprovider=None,
  638. authextra=None,
  639. resumed=None,
  640. resumable=None,
  641. resume_token=None,
  642. custom=None):
  643. """
  644. :param session: The WAMP session ID the other peer is assigned.
  645. :type session: int
  646. :param roles: The WAMP roles to announce.
  647. :type roles: dict of :class:`autobahn.wamp.role.RoleFeatures`
  648. :param realm: The effective realm the session is joined on.
  649. :type realm: str or None
  650. :param authid: The authentication ID assigned.
  651. :type authid: str or None
  652. :param authrole: The authentication role assigned.
  653. :type authrole: str or None
  654. :param authmethod: The authentication method in use.
  655. :type authmethod: str or None
  656. :param authprovider: The authentication provided in use.
  657. :type authprovider: str or None
  658. :param authextra: Application-specific "extra data" to be forwarded to the client.
  659. :type authextra: arbitrary or None
  660. :param resumed: Whether the session is a resumed one.
  661. :type resumed: bool or None
  662. :param resumable: Whether this session can be resumed later.
  663. :type resumable: bool or None
  664. :param resume_token: The secure authorisation token to resume the session.
  665. :type resume_token: str or None
  666. :param custom: Implementation-specific "custom attributes" (`x_my_impl_attribute`) to be set.
  667. :type custom: dict or None
  668. """
  669. assert(type(session) in six.integer_types)
  670. assert(type(roles) == dict)
  671. assert(len(roles) > 0)
  672. for role in roles:
  673. assert(role in [u'broker', u'dealer'])
  674. assert(isinstance(roles[role], autobahn.wamp.role.ROLE_NAME_TO_CLASS[role]))
  675. assert(realm is None or type(realm) == six.text_type)
  676. assert(authid is None or type(authid) == six.text_type)
  677. assert(authrole is None or type(authrole) == six.text_type)
  678. assert(authmethod is None or type(authmethod) == six.text_type)
  679. assert(authprovider is None or type(authprovider) == six.text_type)
  680. assert(authextra is None or type(authextra) == dict)
  681. assert(resumed is None or type(resumed) == bool)
  682. assert(resumable is None or type(resumable) == bool)
  683. assert(resume_token is None or type(resume_token) == six.text_type)
  684. assert(custom is None or type(custom) == dict)
  685. if custom:
  686. for k in custom:
  687. assert(_CUSTOM_ATTRIBUTE.match(k))
  688. Message.__init__(self)
  689. self.session = session
  690. self.roles = roles
  691. self.realm = realm
  692. self.authid = authid
  693. self.authrole = authrole
  694. self.authmethod = authmethod
  695. self.authprovider = authprovider
  696. self.authextra = authextra
  697. self.resumed = resumed
  698. self.resumable = resumable
  699. self.resume_token = resume_token
  700. self.custom = custom or {}
  701. @staticmethod
  702. def parse(wmsg):
  703. """
  704. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  705. :param wmsg: The unserialized raw message.
  706. :type wmsg: list
  707. :returns: An instance of this class.
  708. """
  709. # this should already be verified by WampSerializer.unserialize
  710. assert(len(wmsg) > 0 and wmsg[0] == Welcome.MESSAGE_TYPE)
  711. if len(wmsg) != 3:
  712. raise ProtocolError("invalid message length {0} for WELCOME".format(len(wmsg)))
  713. session = check_or_raise_id(wmsg[1], u"'session' in WELCOME")
  714. details = check_or_raise_extra(wmsg[2], u"'details' in WELCOME")
  715. # FIXME: tigher value checking (types, URIs etc)
  716. realm = details.get(u'realm', None)
  717. authid = details.get(u'authid', None)
  718. authrole = details.get(u'authrole', None)
  719. authmethod = details.get(u'authmethod', None)
  720. authprovider = details.get(u'authprovider', None)
  721. authextra = details.get(u'authextra', None)
  722. resumed = None
  723. if u'resumed' in details:
  724. resumed = details[u'resumed']
  725. if not type(resumed) == bool:
  726. raise ProtocolError("invalid type {0} for 'resumed' detail in WELCOME".format(type(resumed)))
  727. resumable = None
  728. if u'resumable' in details:
  729. resumable = details[u'resumable']
  730. if not type(resumable) == bool:
  731. raise ProtocolError("invalid type {0} for 'resumable' detail in WELCOME".format(type(resumable)))
  732. resume_token = None
  733. if u'resume_token' in details:
  734. resume_token = details[u'resume_token']
  735. if not type(resume_token) == six.text_type:
  736. raise ProtocolError("invalid type {0} for 'resume_token' detail in WELCOME".format(type(resume_token)))
  737. elif resumable:
  738. raise ProtocolError("resume_token required when resumable is given in WELCOME")
  739. roles = {}
  740. if u'roles' not in details:
  741. raise ProtocolError(u"missing mandatory roles attribute in options in WELCOME")
  742. details_roles = check_or_raise_extra(details['roles'], u"'roles' in 'details' in WELCOME")
  743. if len(details_roles) == 0:
  744. raise ProtocolError(u"empty 'roles' in 'details' in WELCOME")
  745. for role in details_roles:
  746. if role not in [u'broker', u'dealer']:
  747. raise ProtocolError("invalid role '{0}' in 'roles' in 'details' in WELCOME".format(role))
  748. role_cls = ROLE_NAME_TO_CLASS[role]
  749. details_role = check_or_raise_extra(details_roles[role], "role '{0}' in 'roles' in 'details' in WELCOME".format(role))
  750. if u'features' in details_role:
  751. check_or_raise_extra(details_role[u'features'], "'features' in role '{0}' in 'roles' in 'details' in WELCOME".format(role))
  752. role_features = role_cls(**details_roles[role][u'features'])
  753. else:
  754. role_features = role_cls()
  755. roles[role] = role_features
  756. custom = {}
  757. for k in details:
  758. if _CUSTOM_ATTRIBUTE.match(k):
  759. custom[k] = details[k]
  760. obj = Welcome(session, roles, realm, authid, authrole, authmethod, authprovider, authextra, resumed, resumable, resume_token, custom)
  761. return obj
  762. def marshal(self):
  763. """
  764. Marshal this object into a raw message for subsequent serialization to bytes.
  765. :returns: The serialized raw message.
  766. :rtype: list
  767. """
  768. details = {}
  769. details.update(self.custom)
  770. if self.realm:
  771. details[u'realm'] = self.realm
  772. if self.authid:
  773. details[u'authid'] = self.authid
  774. if self.authrole:
  775. details[u'authrole'] = self.authrole
  776. if self.authrole:
  777. details[u'authmethod'] = self.authmethod
  778. if self.authprovider:
  779. details[u'authprovider'] = self.authprovider
  780. if self.authextra:
  781. details[u'authextra'] = self.authextra
  782. if self.resumed:
  783. details[u'resumed'] = self.resumed
  784. if self.resumable:
  785. details[u'resumable'] = self.resumable
  786. if self.resume_token:
  787. details[u'resume_token'] = self.resume_token
  788. details[u'roles'] = {}
  789. for role in self.roles.values():
  790. details[u'roles'][role.ROLE] = {}
  791. for feature in role.__dict__:
  792. if not feature.startswith('_') and feature != 'ROLE' and getattr(role, feature) is not None:
  793. if u'features' not in details[u'roles'][role.ROLE]:
  794. details[u'roles'][role.ROLE] = {u'features': {}}
  795. details[u'roles'][role.ROLE][u'features'][six.u(feature)] = getattr(role, feature)
  796. return [Welcome.MESSAGE_TYPE, self.session, details]
  797. def __str__(self):
  798. """
  799. Returns string representation of this message.
  800. """
  801. return u"Welcome(session={}, roles={}, realm={}, authid={}, authrole={}, authmethod={}, authprovider={}, authextra={}, resumed={}, resumable={}, resume_token={})".format(self.session, self.roles, self.realm, self.authid, self.authrole, self.authmethod, self.authprovider, self.authextra, self.resumed, self.resumable, self.resume_token)
  802. class Abort(Message):
  803. """
  804. A WAMP ``ABORT`` message.
  805. Format: ``[ABORT, Details|dict, Reason|uri]``
  806. """
  807. MESSAGE_TYPE = 3
  808. """
  809. The WAMP message code for this type of message.
  810. """
  811. __slots__ = (
  812. 'reason',
  813. 'message',
  814. )
  815. def __init__(self, reason, message=None):
  816. """
  817. :param reason: WAMP or application error URI for aborting reason.
  818. :type reason: str
  819. :param message: Optional human-readable closing message, e.g. for logging purposes.
  820. :type message: str or None
  821. """
  822. assert(type(reason) == six.text_type)
  823. assert(message is None or type(message) == six.text_type)
  824. Message.__init__(self)
  825. self.reason = reason
  826. self.message = message
  827. @staticmethod
  828. def parse(wmsg):
  829. """
  830. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  831. :param wmsg: The unserialized raw message.
  832. :type wmsg: list
  833. :returns: An instance of this class.
  834. """
  835. # this should already be verified by WampSerializer.unserialize
  836. assert(len(wmsg) > 0 and wmsg[0] == Abort.MESSAGE_TYPE)
  837. if len(wmsg) != 3:
  838. raise ProtocolError("invalid message length {0} for ABORT".format(len(wmsg)))
  839. details = check_or_raise_extra(wmsg[1], u"'details' in ABORT")
  840. reason = check_or_raise_uri(wmsg[2], u"'reason' in ABORT")
  841. message = None
  842. if u'message' in details:
  843. details_message = details[u'message']
  844. if type(details_message) != six.text_type:
  845. raise ProtocolError("invalid type {0} for 'message' detail in ABORT".format(type(details_message)))
  846. message = details_message
  847. obj = Abort(reason, message)
  848. return obj
  849. def marshal(self):
  850. """
  851. Marshal this object into a raw message for subsequent serialization to bytes.
  852. :returns: The serialized raw message.
  853. :rtype: list
  854. """
  855. details = {}
  856. if self.message:
  857. details[u'message'] = self.message
  858. return [Abort.MESSAGE_TYPE, details, self.reason]
  859. def __str__(self):
  860. """
  861. Returns string representation of this message.
  862. """
  863. return u"Abort(message={0}, reason={1})".format(self.message, self.reason)
  864. class Challenge(Message):
  865. """
  866. A WAMP ``CHALLENGE`` message.
  867. Format: ``[CHALLENGE, Method|string, Extra|dict]``
  868. """
  869. MESSAGE_TYPE = 4
  870. """
  871. The WAMP message code for this type of message.
  872. """
  873. __slots__ = (
  874. 'method',
  875. 'extra',
  876. )
  877. def __init__(self, method, extra=None):
  878. """
  879. :param method: The authentication method.
  880. :type method: str
  881. :param extra: Authentication method specific information.
  882. :type extra: dict or None
  883. """
  884. assert(type(method) == six.text_type)
  885. assert(extra is None or type(extra) == dict)
  886. Message.__init__(self)
  887. self.method = method
  888. self.extra = extra or {}
  889. @staticmethod
  890. def parse(wmsg):
  891. """
  892. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  893. :param wmsg: The unserialized raw message.
  894. :type wmsg: list
  895. :returns: An instance of this class.
  896. """
  897. # this should already be verified by WampSerializer.unserialize
  898. assert(len(wmsg) > 0 and wmsg[0] == Challenge.MESSAGE_TYPE)
  899. if len(wmsg) != 3:
  900. raise ProtocolError("invalid message length {0} for CHALLENGE".format(len(wmsg)))
  901. method = wmsg[1]
  902. if type(method) != six.text_type:
  903. raise ProtocolError("invalid type {0} for 'method' in CHALLENGE".format(type(method)))
  904. extra = check_or_raise_extra(wmsg[2], u"'extra' in CHALLENGE")
  905. obj = Challenge(method, extra)
  906. return obj
  907. def marshal(self):
  908. """
  909. Marshal this object into a raw message for subsequent serialization to bytes.
  910. :returns: The serialized raw message.
  911. :rtype: list
  912. """
  913. return [Challenge.MESSAGE_TYPE, self.method, self.extra]
  914. def __str__(self):
  915. """
  916. Returns string representation of this message.
  917. """
  918. return u"Challenge(method={0}, extra={1})".format(self.method, self.extra)
  919. class Authenticate(Message):
  920. """
  921. A WAMP ``AUTHENTICATE`` message.
  922. Format: ``[AUTHENTICATE, Signature|string, Extra|dict]``
  923. """
  924. MESSAGE_TYPE = 5
  925. """
  926. The WAMP message code for this type of message.
  927. """
  928. __slots__ = (
  929. 'signature',
  930. 'extra',
  931. )
  932. def __init__(self, signature, extra=None):
  933. """
  934. :param signature: The signature for the authentication challenge.
  935. :type signature: str
  936. :param extra: Authentication method specific information.
  937. :type extra: dict or None
  938. """
  939. assert(type(signature) == six.text_type)
  940. assert(extra is None or type(extra) == dict)
  941. Message.__init__(self)
  942. self.signature = signature
  943. self.extra = extra or {}
  944. @staticmethod
  945. def parse(wmsg):
  946. """
  947. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  948. :param wmsg: The unserialized raw message.
  949. :type wmsg: list
  950. :returns: An instance of this class.
  951. """
  952. # this should already be verified by WampSerializer.unserialize
  953. assert(len(wmsg) > 0 and wmsg[0] == Authenticate.MESSAGE_TYPE)
  954. if len(wmsg) != 3:
  955. raise ProtocolError("invalid message length {0} for AUTHENTICATE".format(len(wmsg)))
  956. signature = wmsg[1]
  957. if type(signature) != six.text_type:
  958. raise ProtocolError("invalid type {0} for 'signature' in AUTHENTICATE".format(type(signature)))
  959. extra = check_or_raise_extra(wmsg[2], u"'extra' in AUTHENTICATE")
  960. obj = Authenticate(signature, extra)
  961. return obj
  962. def marshal(self):
  963. """
  964. Marshal this object into a raw message for subsequent serialization to bytes.
  965. :returns: The serialized raw message.
  966. :rtype: list
  967. """
  968. return [Authenticate.MESSAGE_TYPE, self.signature, self.extra]
  969. def __str__(self):
  970. """
  971. Returns string representation of this message.
  972. """
  973. return u"Authenticate(signature={0}, extra={1})".format(self.signature, self.extra)
  974. class Goodbye(Message):
  975. """
  976. A WAMP ``GOODBYE`` message.
  977. Format: ``[GOODBYE, Details|dict, Reason|uri]``
  978. """
  979. MESSAGE_TYPE = 6
  980. """
  981. The WAMP message code for this type of message.
  982. """
  983. DEFAULT_REASON = u"wamp.close.normal"
  984. """
  985. Default WAMP closing reason.
  986. """
  987. __slots__ = (
  988. 'reason',
  989. 'message',
  990. 'resumable',
  991. )
  992. def __init__(self, reason=DEFAULT_REASON, message=None, resumable=None):
  993. """
  994. :param reason: Optional WAMP or application error URI for closing reason.
  995. :type reason: str
  996. :param message: Optional human-readable closing message, e.g. for logging purposes.
  997. :type message: str or None
  998. :param resumable: From the server: Whether the session is able to be resumed (true) or destroyed (false). From the client: Whether it should be resumable (true) or destroyed (false).
  999. :type resumable: bool or None
  1000. """
  1001. assert(type(reason) == six.text_type)
  1002. assert(message is None or type(message) == six.text_type)
  1003. assert(resumable is None or type(resumable) == bool)
  1004. Message.__init__(self)
  1005. self.reason = reason
  1006. self.message = message
  1007. self.resumable = resumable
  1008. @staticmethod
  1009. def parse(wmsg):
  1010. """
  1011. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  1012. :param wmsg: The unserialized raw message.
  1013. :type wmsg: list
  1014. :returns: An instance of this class.
  1015. """
  1016. # this should already be verified by WampSerializer.unserialize
  1017. assert(len(wmsg) > 0 and wmsg[0] == Goodbye.MESSAGE_TYPE)
  1018. if len(wmsg) != 3:
  1019. raise ProtocolError("invalid message length {0} for GOODBYE".format(len(wmsg)))
  1020. details = check_or_raise_extra(wmsg[1], u"'details' in GOODBYE")
  1021. reason = check_or_raise_uri(wmsg[2], u"'reason' in GOODBYE")
  1022. message = None
  1023. resumable = None
  1024. if u'message' in details:
  1025. details_message = details[u'message']
  1026. if type(details_message) != six.text_type:
  1027. raise ProtocolError("invalid type {0} for 'message' detail in GOODBYE".format(type(details_message)))
  1028. message = details_message
  1029. if u'resumable' in details:
  1030. resumable = details[u'resumable']
  1031. if type(resumable) != bool:
  1032. raise ProtocolError("invalid type {0} for 'resumable' detail in GOODBYE".format(type(resumable)))
  1033. obj = Goodbye(reason=reason,
  1034. message=message,
  1035. resumable=resumable)
  1036. return obj
  1037. def marshal(self):
  1038. """
  1039. Marshal this object into a raw message for subsequent serialization to bytes.
  1040. :returns: The serialized raw message.
  1041. :rtype: list
  1042. """
  1043. details = {}
  1044. if self.message:
  1045. details[u'message'] = self.message
  1046. if self.resumable:
  1047. details[u'resumable'] = self.resumable
  1048. return [Goodbye.MESSAGE_TYPE, details, self.reason]
  1049. def __str__(self):
  1050. """
  1051. Returns string representation of this message.
  1052. """
  1053. return u"Goodbye(message={}, reason={}, resumable={})".format(self.message, self.reason, self.resumable)
  1054. class Error(Message):
  1055. """
  1056. A WAMP ``ERROR`` message.
  1057. Formats:
  1058. * ``[ERROR, REQUEST.Type|int, REQUEST.Request|id, Details|dict, Error|uri]``
  1059. * ``[ERROR, REQUEST.Type|int, REQUEST.Request|id, Details|dict, Error|uri, Arguments|list]``
  1060. * ``[ERROR, REQUEST.Type|int, REQUEST.Request|id, Details|dict, Error|uri, Arguments|list, ArgumentsKw|dict]``
  1061. * ``[ERROR, REQUEST.Type|int, REQUEST.Request|id, Details|dict, Error|uri, Payload|binary]``
  1062. """
  1063. MESSAGE_TYPE = 8
  1064. """
  1065. The WAMP message code for this type of message.
  1066. """
  1067. __slots__ = (
  1068. 'request_type',
  1069. 'request',
  1070. 'error',
  1071. 'args',
  1072. 'kwargs',
  1073. 'payload',
  1074. 'enc_algo',
  1075. 'enc_key',
  1076. 'enc_serializer',
  1077. 'callee',
  1078. 'callee_authid',
  1079. 'callee_authrole',
  1080. 'forward_for',
  1081. )
  1082. def __init__(self,
  1083. request_type,
  1084. request,
  1085. error,
  1086. args=None,
  1087. kwargs=None,
  1088. payload=None,
  1089. enc_algo=None,
  1090. enc_key=None,
  1091. enc_serializer=None,
  1092. callee=None,
  1093. callee_authid=None,
  1094. callee_authrole=None,
  1095. forward_for=None):
  1096. """
  1097. :param request_type: The WAMP message type code for the original request.
  1098. :type request_type: int
  1099. :param request: The WAMP request ID of the original request (`Call`, `Subscribe`, ...) this error occurred for.
  1100. :type request: int
  1101. :param error: The WAMP or application error URI for the error that occurred.
  1102. :type error: str
  1103. :param args: Positional values for application-defined exception.
  1104. Must be serializable using any serializers in use.
  1105. :type args: list or None
  1106. :param kwargs: Keyword values for application-defined exception.
  1107. Must be serializable using any serializers in use.
  1108. :type kwargs: dict or None
  1109. :param payload: Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
  1110. :type payload: bytes or None
  1111. :param enc_algo: If using payload transparency, the encoding algorithm that was used to encode the payload.
  1112. :type enc_algo: str or None
  1113. :param enc_key: If using payload transparency with an encryption algorithm, the payload encryption key.
  1114. :type enc_key: str or None
  1115. :param enc_serializer: If using payload transparency, the payload object serializer that was used encoding the payload.
  1116. :type enc_serializer: str or None
  1117. :param callee: The WAMP session ID of the effective callee that responded with the error. Only filled if callee is disclosed.
  1118. :type callee: None or int
  1119. :param callee_authid: The WAMP authid of the responding callee. Only filled if callee is disclosed.
  1120. :type callee_authid: None or unicode
  1121. :param callee_authrole: The WAMP authrole of the responding callee. Only filled if callee is disclosed.
  1122. :type callee_authrole: None or unicode
  1123. :param forward_for: When this Error is forwarded for a client/callee (or from an intermediary router).
  1124. :type forward_for: list[dict]
  1125. """
  1126. assert(type(request_type) in six.integer_types)
  1127. assert(type(request) in six.integer_types)
  1128. assert(type(error) == six.text_type)
  1129. assert(args is None or type(args) in [list, tuple])
  1130. assert(kwargs is None or type(kwargs) == dict)
  1131. assert(payload is None or type(payload) == six.binary_type)
  1132. assert(payload is None or (payload is not None and args is None and kwargs is None))
  1133. assert(enc_algo is None or is_valid_enc_algo(enc_algo))
  1134. assert((enc_algo is None and enc_key is None and enc_serializer is None) or (payload is not None and enc_algo is not None))
  1135. assert(enc_key is None or type(enc_key) == six.text_type)
  1136. assert(enc_serializer is None or is_valid_enc_serializer(enc_serializer))
  1137. assert(callee is None or type(callee) in six.integer_types)
  1138. assert(callee_authid is None or type(callee_authid) == six.text_type)
  1139. assert(callee_authrole is None or type(callee_authrole) == six.text_type)
  1140. assert(forward_for is None or type(forward_for) == list)
  1141. if forward_for:
  1142. for ff in forward_for:
  1143. assert type(ff) == dict
  1144. assert 'session' in ff and type(ff['session']) in six.integer_types
  1145. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  1146. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  1147. Message.__init__(self)
  1148. self.request_type = request_type
  1149. self.request = request
  1150. self.error = error
  1151. self.args = args
  1152. self.kwargs = _validate_kwargs(kwargs)
  1153. self.payload = payload
  1154. # payload transparency related knobs
  1155. self.enc_algo = enc_algo
  1156. self.enc_key = enc_key
  1157. self.enc_serializer = enc_serializer
  1158. # effective callee that responded with the error
  1159. self.callee = callee
  1160. self.callee_authid = callee_authid
  1161. self.callee_authrole = callee_authrole
  1162. # message forwarding
  1163. self.forward_for = forward_for
  1164. @staticmethod
  1165. def parse(wmsg):
  1166. """
  1167. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  1168. :param wmsg: The unserialized raw message.
  1169. :type wmsg: list
  1170. :returns: An instance of this class.
  1171. """
  1172. # this should already be verified by WampSerializer.unserialize
  1173. assert(len(wmsg) > 0 and wmsg[0] == Error.MESSAGE_TYPE)
  1174. if len(wmsg) not in (5, 6, 7):
  1175. raise ProtocolError("invalid message length {0} for ERROR".format(len(wmsg)))
  1176. request_type = wmsg[1]
  1177. if type(request_type) not in six.integer_types:
  1178. raise ProtocolError("invalid type {0} for 'request_type' in ERROR".format(request_type))
  1179. if request_type not in [Subscribe.MESSAGE_TYPE,
  1180. Unsubscribe.MESSAGE_TYPE,
  1181. Publish.MESSAGE_TYPE,
  1182. Register.MESSAGE_TYPE,
  1183. Unregister.MESSAGE_TYPE,
  1184. Call.MESSAGE_TYPE,
  1185. Invocation.MESSAGE_TYPE]:
  1186. raise ProtocolError("invalid value {0} for 'request_type' in ERROR".format(request_type))
  1187. request = check_or_raise_id(wmsg[2], u"'request' in ERROR")
  1188. details = check_or_raise_extra(wmsg[3], u"'details' in ERROR")
  1189. error = check_or_raise_uri(wmsg[4], u"'error' in ERROR")
  1190. args = None
  1191. kwargs = None
  1192. payload = None
  1193. enc_algo = None
  1194. enc_key = None
  1195. enc_serializer = None
  1196. callee = None
  1197. callee_authid = None
  1198. callee_authrole = None
  1199. forward_for = None
  1200. if len(wmsg) == 6 and type(wmsg[5]) == six.binary_type:
  1201. payload = wmsg[5]
  1202. enc_algo = details.get(u'enc_algo', None)
  1203. if enc_algo and not is_valid_enc_algo(enc_algo):
  1204. raise ProtocolError("invalid value {0} for 'enc_algo' detail in EVENT".format(enc_algo))
  1205. enc_key = details.get(u'enc_key', None)
  1206. if enc_key and type(enc_key) != six.text_type:
  1207. raise ProtocolError("invalid type {0} for 'enc_key' detail in EVENT".format(type(enc_key)))
  1208. enc_serializer = details.get(u'enc_serializer', None)
  1209. if enc_serializer and not is_valid_enc_serializer(enc_serializer):
  1210. raise ProtocolError("invalid value {0} for 'enc_serializer' detail in EVENT".format(enc_serializer))
  1211. else:
  1212. if len(wmsg) > 5:
  1213. args = wmsg[5]
  1214. if args is not None and type(args) != list:
  1215. raise ProtocolError("invalid type {0} for 'args' in ERROR".format(type(args)))
  1216. if len(wmsg) > 6:
  1217. kwargs = wmsg[6]
  1218. if type(kwargs) != dict:
  1219. raise ProtocolError("invalid type {0} for 'kwargs' in ERROR".format(type(kwargs)))
  1220. if u'callee' in details:
  1221. detail_callee = details[u'callee']
  1222. if type(detail_callee) not in six.integer_types:
  1223. raise ProtocolError("invalid type {0} for 'callee' detail in ERROR".format(type(detail_callee)))
  1224. callee = detail_callee
  1225. if u'callee_authid' in details:
  1226. detail_callee_authid = details[u'callee_authid']
  1227. if type(detail_callee_authid) != six.text_type:
  1228. raise ProtocolError("invalid type {0} for 'callee_authid' detail in ERROR".format(type(detail_callee_authid)))
  1229. callee_authid = detail_callee_authid
  1230. if u'callee_authrole' in details:
  1231. detail_callee_authrole = details[u'callee_authrole']
  1232. if type(detail_callee_authrole) != six.text_type:
  1233. raise ProtocolError("invalid type {0} for 'callee_authrole' detail in ERROR".format(type(detail_callee_authrole)))
  1234. callee_authrole = detail_callee_authrole
  1235. if u'forward_for' in details:
  1236. forward_for = details[u'forward_for']
  1237. valid = False
  1238. if type(forward_for) == list:
  1239. for ff in forward_for:
  1240. if type(ff) != dict:
  1241. break
  1242. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  1243. break
  1244. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  1245. break
  1246. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  1247. break
  1248. valid = True
  1249. if not valid:
  1250. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in ERROR")
  1251. obj = Error(request_type,
  1252. request,
  1253. error,
  1254. args=args,
  1255. kwargs=kwargs,
  1256. payload=payload,
  1257. enc_algo=enc_algo,
  1258. enc_key=enc_key,
  1259. enc_serializer=enc_serializer,
  1260. callee=callee,
  1261. callee_authid=callee_authid,
  1262. callee_authrole=callee_authrole,
  1263. forward_for=forward_for)
  1264. return obj
  1265. def marshal(self):
  1266. """
  1267. Marshal this object into a raw message for subsequent serialization to bytes.
  1268. :returns: The serialized raw message.
  1269. :rtype: list
  1270. """
  1271. details = {}
  1272. if self.callee is not None:
  1273. details[u'callee'] = self.callee
  1274. if self.callee_authid is not None:
  1275. details[u'callee_authid'] = self.callee_authid
  1276. if self.callee_authrole is not None:
  1277. details[u'callee_authrole'] = self.callee_authrole
  1278. if self.forward_for is not None:
  1279. details[u'forward_for'] = self.forward_for
  1280. if self.payload:
  1281. if self.enc_algo is not None:
  1282. details[u'enc_algo'] = self.enc_algo
  1283. if self.enc_key is not None:
  1284. details[u'enc_key'] = self.enc_key
  1285. if self.enc_serializer is not None:
  1286. details[u'enc_serializer'] = self.enc_serializer
  1287. return [self.MESSAGE_TYPE, self.request_type, self.request, details, self.error, self.payload]
  1288. else:
  1289. if self.kwargs:
  1290. return [self.MESSAGE_TYPE, self.request_type, self.request, details, self.error, self.args, self.kwargs]
  1291. elif self.args:
  1292. return [self.MESSAGE_TYPE, self.request_type, self.request, details, self.error, self.args]
  1293. else:
  1294. return [self.MESSAGE_TYPE, self.request_type, self.request, details, self.error]
  1295. def __str__(self):
  1296. """
  1297. Returns string representation of this message.
  1298. """
  1299. return u"Error(request_type={0}, request={1}, error={2}, args={3}, kwargs={4}, enc_algo={5}, enc_key={6}, enc_serializer={7}, payload={8}, callee={9}, callee_authid={10}, callee_authrole={11}, forward_for={12})".format(self.request_type, self.request, self.error, self.args, self.kwargs, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), self.callee, self.callee_authid, self.callee_authrole, self.forward_for)
  1300. class Publish(Message):
  1301. """
  1302. A WAMP ``PUBLISH`` message.
  1303. Formats:
  1304. * ``[PUBLISH, Request|id, Options|dict, Topic|uri]``
  1305. * ``[PUBLISH, Request|id, Options|dict, Topic|uri, Arguments|list]``
  1306. * ``[PUBLISH, Request|id, Options|dict, Topic|uri, Arguments|list, ArgumentsKw|dict]``
  1307. * ``[PUBLISH, Request|id, Options|dict, Topic|uri, Payload|binary]``
  1308. """
  1309. MESSAGE_TYPE = 16
  1310. """
  1311. The WAMP message code for this type of message.
  1312. """
  1313. __slots__ = (
  1314. # uint64 (key)
  1315. '_request',
  1316. # string (required, uri)
  1317. '_topic',
  1318. # [uint8]
  1319. '_args',
  1320. # [uint8]
  1321. '_kwargs',
  1322. # [uint8]
  1323. '_payload',
  1324. # Payload => uint8
  1325. '_enc_algo',
  1326. # Serializer => uint8
  1327. '_enc_serializer',
  1328. # [uint8]
  1329. '_enc_key',
  1330. # bool
  1331. '_acknowledge',
  1332. # bool
  1333. '_exclude_me',
  1334. # [uint64]
  1335. '_exclude',
  1336. # [string] (principal)
  1337. '_exclude_authid',
  1338. # [string] (principal)
  1339. '_exclude_authrole',
  1340. # [uint64]
  1341. '_eligible',
  1342. # [string] (principal)
  1343. '_eligible_authid',
  1344. # [string] (principal)
  1345. '_eligible_authrole',
  1346. # bool
  1347. '_retain',
  1348. # [Principal]
  1349. '_forward_for',
  1350. )
  1351. def __init__(self,
  1352. request=None,
  1353. topic=None,
  1354. args=None,
  1355. kwargs=None,
  1356. payload=None,
  1357. acknowledge=None,
  1358. exclude_me=None,
  1359. exclude=None,
  1360. exclude_authid=None,
  1361. exclude_authrole=None,
  1362. eligible=None,
  1363. eligible_authid=None,
  1364. eligible_authrole=None,
  1365. retain=None,
  1366. enc_algo=None,
  1367. enc_key=None,
  1368. enc_serializer=None,
  1369. forward_for=None,
  1370. from_fbs=None):
  1371. """
  1372. :param request: The WAMP request ID of this request.
  1373. :type request: int
  1374. :param topic: The WAMP or application URI of the PubSub topic the event should
  1375. be published to.
  1376. :type topic: str
  1377. :param args: Positional values for application-defined event payload.
  1378. Must be serializable using any serializers in use.
  1379. :type args: list or tuple or None
  1380. :param kwargs: Keyword values for application-defined event payload.
  1381. Must be serializable using any serializers in use.
  1382. :type kwargs: dict or None
  1383. :param payload: Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
  1384. :type payload: bytes or None
  1385. :param acknowledge: If True, acknowledge the publication with a success or
  1386. error response.
  1387. :type acknowledge: bool or None
  1388. :param exclude_me: If ``True``, exclude the publisher from receiving the event, even
  1389. if he is subscribed (and eligible).
  1390. :type exclude_me: bool or None
  1391. :param exclude: List of WAMP session IDs to exclude from receiving this event.
  1392. :type exclude: list of int or None
  1393. :param exclude_authid: List of WAMP authids to exclude from receiving this event.
  1394. :type exclude_authid: list of str or None
  1395. :param exclude_authrole: List of WAMP authroles to exclude from receiving this event.
  1396. :type exclude_authrole: list of str or None
  1397. :param eligible: List of WAMP session IDs eligible to receive this event.
  1398. :type eligible: list of int or None
  1399. :param eligible_authid: List of WAMP authids eligible to receive this event.
  1400. :type eligible_authid: list of str or None
  1401. :param eligible_authrole: List of WAMP authroles eligible to receive this event.
  1402. :type eligible_authrole: list of str or None
  1403. :param retain: If ``True``, request the broker retain this event.
  1404. :type retain: bool or None
  1405. :param enc_algo: If using payload transparency, the encoding algorithm that was used to encode the payload.
  1406. :type enc_algo: str or None
  1407. :param enc_key: If using payload transparency with an encryption algorithm, the payload encryption key.
  1408. :type enc_key: str or None
  1409. :param enc_serializer: If using payload transparency, the payload object serializer that was used encoding the payload.
  1410. :type enc_serializer: str or None or None
  1411. :param forward_for: When this Call is forwarded for a client (or from an intermediary router).
  1412. :type forward_for: list[dict]
  1413. """
  1414. assert(request is None or type(request) in six.integer_types)
  1415. assert(topic is None or type(topic) == six.text_type)
  1416. assert(args is None or type(args) in [list, tuple, six.text_type, six.binary_type])
  1417. assert(kwargs is None or type(kwargs) in [dict, six.text_type, six.binary_type])
  1418. assert(payload is None or type(payload) == six.binary_type)
  1419. assert(payload is None or (payload is not None and args is None and kwargs is None))
  1420. assert(acknowledge is None or type(acknowledge) == bool)
  1421. assert(retain is None or type(retain) == bool)
  1422. # publisher exlusion and black-/whitelisting
  1423. assert(exclude_me is None or type(exclude_me) == bool)
  1424. assert(exclude is None or type(exclude) == list)
  1425. if exclude:
  1426. for sessionid in exclude:
  1427. assert(type(sessionid) in six.integer_types)
  1428. assert(exclude_authid is None or type(exclude_authid) == list)
  1429. if exclude_authid:
  1430. for authid in exclude_authid:
  1431. assert(type(authid) == six.text_type)
  1432. assert(exclude_authrole is None or type(exclude_authrole) == list)
  1433. if exclude_authrole:
  1434. for authrole in exclude_authrole:
  1435. assert(type(authrole) == six.text_type)
  1436. assert(eligible is None or type(eligible) == list)
  1437. if eligible:
  1438. for sessionid in eligible:
  1439. assert(type(sessionid) in six.integer_types)
  1440. assert(eligible_authid is None or type(eligible_authid) == list)
  1441. if eligible_authid:
  1442. for authid in eligible_authid:
  1443. assert(type(authid) == six.text_type)
  1444. assert(eligible_authrole is None or type(eligible_authrole) == list)
  1445. if eligible_authrole:
  1446. for authrole in eligible_authrole:
  1447. assert(type(authrole) == six.text_type)
  1448. assert(enc_algo is None or is_valid_enc_algo(enc_algo))
  1449. assert((enc_algo is None and enc_key is None and enc_serializer is None) or (payload is not None and enc_algo is not None))
  1450. assert(enc_key is None or type(enc_key) == six.text_type)
  1451. assert(enc_serializer is None or is_valid_enc_serializer(enc_serializer))
  1452. assert(forward_for is None or type(forward_for) == list)
  1453. if forward_for:
  1454. for ff in forward_for:
  1455. assert type(ff) == dict
  1456. assert 'session' in ff and type(ff['session']) in six.integer_types
  1457. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  1458. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  1459. Message.__init__(self, from_fbs=from_fbs)
  1460. self._request = request
  1461. self._topic = topic
  1462. self._args = args
  1463. self._kwargs = _validate_kwargs(kwargs)
  1464. self._payload = payload
  1465. self._acknowledge = acknowledge
  1466. # publisher exlusion and black-/whitelisting
  1467. self._exclude_me = exclude_me
  1468. self._exclude = exclude
  1469. self._exclude_authid = exclude_authid
  1470. self._exclude_authrole = exclude_authrole
  1471. self._eligible = eligible
  1472. self._eligible_authid = eligible_authid
  1473. self._eligible_authrole = eligible_authrole
  1474. # event retention
  1475. self._retain = retain
  1476. # payload transparency related knobs
  1477. self._enc_algo = enc_algo
  1478. self._enc_key = enc_key
  1479. self._enc_serializer = enc_serializer
  1480. # message forwarding
  1481. self._forward_for = forward_for
  1482. def __eq__(self, other):
  1483. if not isinstance(other, self.__class__):
  1484. return False
  1485. if not Message.__eq__(self, other):
  1486. return False
  1487. if other.request != self.request:
  1488. return False
  1489. if other.topic != self.topic:
  1490. return False
  1491. if other.args != self.args:
  1492. return False
  1493. if other.kwargs != self.kwargs:
  1494. return False
  1495. if other.payload != self.payload:
  1496. return False
  1497. if other.acknowledge != self.acknowledge:
  1498. return False
  1499. if other.exclude_me != self.exclude_me:
  1500. return False
  1501. if other.exclude != self.exclude:
  1502. return False
  1503. if other.exclude_authid != self.exclude_authid:
  1504. return False
  1505. if other.exclude_authrole != self.exclude_authrole:
  1506. return False
  1507. if other.eligible != self.eligible:
  1508. return False
  1509. if other.eligible_authid != self.eligible_authid:
  1510. return False
  1511. if other.eligible_authrole != self.eligible_authrole:
  1512. return False
  1513. if other.retain != self.retain:
  1514. return False
  1515. if other.enc_algo != self.enc_algo:
  1516. return False
  1517. if other.enc_key != self.enc_key:
  1518. return False
  1519. if other.enc_serializer != self.enc_serializer:
  1520. return False
  1521. if other.forward_for != self.forward_for:
  1522. return False
  1523. return True
  1524. def __ne__(self, other):
  1525. return not self.__eq__(other)
  1526. @property
  1527. def request(self):
  1528. if self._request is None and self._from_fbs:
  1529. self._request = self._from_fbs.Request()
  1530. return self._request
  1531. @request.setter
  1532. def request(self, value):
  1533. assert(value is None or type(value) in six.integer_types)
  1534. self._request = value
  1535. @property
  1536. def topic(self):
  1537. if self._topic is None and self._from_fbs:
  1538. s = self._from_fbs.Topic()
  1539. if s:
  1540. self._topic = s.decode('utf8')
  1541. return self._topic
  1542. @topic.setter
  1543. def topic(self, value):
  1544. assert value is None or type(value) == str
  1545. self._topic = value
  1546. @property
  1547. def args(self):
  1548. if self._args is None and self._from_fbs:
  1549. if self._from_fbs.ArgsLength():
  1550. self._args = cbor.loads(bytes(self._from_fbs.ArgsAsBytes()))
  1551. return self._args
  1552. @args.setter
  1553. def args(self, value):
  1554. assert(value is None or type(value) in [list, tuple])
  1555. self._args = value
  1556. @property
  1557. def kwargs(self):
  1558. if self._kwargs is None and self._from_fbs:
  1559. if self._from_fbs.KwargsLength():
  1560. self._kwargs = cbor.loads(bytes(self._from_fbs.KwargsAsBytes()))
  1561. return self._kwargs
  1562. @kwargs.setter
  1563. def kwargs(self, value):
  1564. assert(value is None or type(value) == dict)
  1565. self._kwargs = value
  1566. @property
  1567. def payload(self):
  1568. if self._payload is None and self._from_fbs:
  1569. if self._from_fbs.PayloadLength():
  1570. self._payload = self._from_fbs.PayloadAsBytes()
  1571. return self._payload
  1572. @payload.setter
  1573. def payload(self, value):
  1574. assert value is None or type(value) == bytes
  1575. self._payload = value
  1576. @property
  1577. def acknowledge(self):
  1578. if self._acknowledge is None and self._from_fbs:
  1579. acknowledge = self._from_fbs.Acknowledge()
  1580. if acknowledge:
  1581. self._acknowledge = acknowledge
  1582. return self._acknowledge
  1583. @acknowledge.setter
  1584. def acknowledge(self, value):
  1585. assert value is None or type(value) == bool
  1586. self._acknowledge = value
  1587. @property
  1588. def exclude_me(self):
  1589. if self._exclude_me is None and self._from_fbs:
  1590. exclude_me = self._from_fbs.ExcludeMe()
  1591. if exclude_me is False:
  1592. self._exclude_me = exclude_me
  1593. return self._exclude_me
  1594. @exclude_me.setter
  1595. def exclude_me(self, value):
  1596. assert value is None or type(value) == bool
  1597. self._exclude_me = value
  1598. @property
  1599. def exclude(self):
  1600. if self._exclude is None and self._from_fbs:
  1601. if self._from_fbs.ExcludeLength():
  1602. exclude = []
  1603. for j in range(self._from_fbs.ExcludeLength()):
  1604. exclude.append(self._from_fbs.Exclude(j))
  1605. self._exclude = exclude
  1606. return self._exclude
  1607. @exclude.setter
  1608. def exclude(self, value):
  1609. assert value is None or type(value) == list
  1610. if value:
  1611. for x in value:
  1612. assert type(x) == int
  1613. self._exclude = value
  1614. @property
  1615. def exclude_authid(self):
  1616. if self._exclude_authid is None and self._from_fbs:
  1617. if self._from_fbs.ExcludeAuthidLength():
  1618. exclude_authid = []
  1619. for j in range(self._from_fbs.ExcludeAuthidLength()):
  1620. exclude_authid.append(self._from_fbs.ExcludeAuthid(j).decode('utf8'))
  1621. self._exclude_authid = exclude_authid
  1622. return self._exclude_authid
  1623. @exclude_authid.setter
  1624. def exclude_authid(self, value):
  1625. assert value is None or type(value) == list
  1626. if value:
  1627. for x in value:
  1628. assert type(x) == str
  1629. self._exclude_authid = value
  1630. @property
  1631. def exclude_authrole(self):
  1632. if self._exclude_authrole is None and self._from_fbs:
  1633. if self._from_fbs.ExcludeAuthroleLength():
  1634. exclude_authrole = []
  1635. for j in range(self._from_fbs.ExcludeAuthroleLength()):
  1636. exclude_authrole.append(self._from_fbs.ExcludeAuthrole(j).decode('utf8'))
  1637. self._exclude_authrole = exclude_authrole
  1638. return self._exclude_authrole
  1639. @exclude_authrole.setter
  1640. def exclude_authrole(self, value):
  1641. assert value is None or type(value) == list
  1642. if value:
  1643. for x in value:
  1644. assert type(x) == str
  1645. self._exclude_authrole = value
  1646. @property
  1647. def eligible(self):
  1648. if self._eligible is None and self._from_fbs:
  1649. if self._from_fbs.EligibleLength():
  1650. eligible = []
  1651. for j in range(self._from_fbs.EligibleLength()):
  1652. eligible.append(self._from_fbs.Eligible(j))
  1653. self._eligible = eligible
  1654. return self._eligible
  1655. @eligible.setter
  1656. def eligible(self, value):
  1657. assert value is None or type(value) == list
  1658. if value:
  1659. for x in value:
  1660. assert type(x) == int
  1661. self._eligible = value
  1662. @property
  1663. def eligible_authid(self):
  1664. if self._eligible_authid is None and self._from_fbs:
  1665. if self._from_fbs.EligibleAuthidLength():
  1666. eligible_authid = []
  1667. for j in range(self._from_fbs.EligibleAuthidLength()):
  1668. eligible_authid.append(self._from_fbs.EligibleAuthid(j).decode('utf8'))
  1669. self._eligible_authid = eligible_authid
  1670. return self._eligible_authid
  1671. @eligible_authid.setter
  1672. def eligible_authid(self, value):
  1673. assert value is None or type(value) == list
  1674. if value:
  1675. for x in value:
  1676. assert type(x) == str
  1677. self._eligible_authid = value
  1678. @property
  1679. def eligible_authrole(self):
  1680. if self._eligible_authrole is None and self._from_fbs:
  1681. if self._from_fbs.EligibleAuthroleLength():
  1682. eligible_authrole = []
  1683. for j in range(self._from_fbs.EligibleAuthroleLength()):
  1684. eligible_authrole.append(self._from_fbs.EligibleAuthrole(j).decode('utf8'))
  1685. self._eligible_authrole = eligible_authrole
  1686. return self._eligible_authrole
  1687. @eligible_authrole.setter
  1688. def eligible_authrole(self, value):
  1689. assert value is None or type(value) == list
  1690. if value:
  1691. for x in value:
  1692. assert type(x) == str
  1693. self._eligible_authrole = value
  1694. @property
  1695. def retain(self):
  1696. if self._retain is None and self._from_fbs:
  1697. retain = self._from_fbs.Retain()
  1698. if retain:
  1699. self._retain = retain
  1700. return self._retain
  1701. @retain.setter
  1702. def retain(self, value):
  1703. assert value is None or type(value) == bool
  1704. self._retain = value
  1705. @property
  1706. def enc_algo(self):
  1707. if self._enc_algo is None and self._from_fbs:
  1708. enc_algo = self._from_fbs.EncAlgo()
  1709. if enc_algo:
  1710. self._enc_algo = enc_algo
  1711. return self._enc_algo
  1712. @enc_algo.setter
  1713. def enc_algo(self, value):
  1714. assert value is None or value in [ENC_ALGO_CRYPTOBOX, ENC_ALGO_MQTT, ENC_ALGO_XBR]
  1715. self._enc_algo = value
  1716. @property
  1717. def enc_key(self):
  1718. if self._enc_key is None and self._from_fbs:
  1719. if self._from_fbs.EncKeyLength():
  1720. self._enc_key = self._from_fbs.EncKeyAsBytes()
  1721. return self._enc_key
  1722. @enc_key.setter
  1723. def enc_key(self, value):
  1724. assert value is None or type(value) == bytes
  1725. self._enc_key = value
  1726. @property
  1727. def enc_serializer(self):
  1728. if self._enc_serializer is None and self._from_fbs:
  1729. enc_serializer = self._from_fbs.EncSerializer()
  1730. if enc_serializer:
  1731. self._enc_serializer = enc_serializer
  1732. return self._enc_serializer
  1733. @enc_serializer.setter
  1734. def enc_serializer(self, value):
  1735. assert value is None or value in [ENC_SER_JSON, ENC_SER_MSGPACK, ENC_SER_CBOR, ENC_SER_UBJSON]
  1736. self._enc_serializer = value
  1737. @property
  1738. def forward_for(self):
  1739. # FIXME
  1740. return self._forward_for
  1741. @forward_for.setter
  1742. def forward_for(self, value):
  1743. # FIXME
  1744. self._forward_for = value
  1745. @staticmethod
  1746. def cast(buf):
  1747. return Publish(from_fbs=message_fbs.Publish.GetRootAsPublish(buf, 0))
  1748. def build(self, builder):
  1749. args = self.args
  1750. if args:
  1751. args = builder.CreateByteVector(cbor.dumps(args))
  1752. kwargs = self.kwargs
  1753. if kwargs:
  1754. kwargs = builder.CreateByteVector(cbor.dumps(kwargs))
  1755. payload = self.payload
  1756. if payload:
  1757. payload = builder.CreateByteVector(payload)
  1758. topic = self.topic
  1759. if topic:
  1760. topic = builder.CreateString(topic)
  1761. enc_key = self.enc_key
  1762. if enc_key:
  1763. enc_key = builder.CreateByteVector(enc_key)
  1764. # exclude: [int]
  1765. exclude = self.exclude
  1766. if exclude:
  1767. message_fbs.PublishGen.PublishStartExcludeAuthidVector(builder, len(exclude))
  1768. for session in reversed(exclude):
  1769. builder.PrependUint64(session)
  1770. exclude = builder.EndVector(len(exclude))
  1771. # exclude_authid: [string]
  1772. exclude_authid = self.exclude_authid
  1773. if exclude_authid:
  1774. _exclude_authid = []
  1775. for authid in exclude_authid:
  1776. _exclude_authid.append(builder.CreateString(authid))
  1777. message_fbs.PublishGen.PublishStartExcludeAuthidVector(builder, len(_exclude_authid))
  1778. for o in reversed(_exclude_authid):
  1779. builder.PrependUOffsetTRelative(o)
  1780. exclude_authid = builder.EndVector(len(_exclude_authid))
  1781. # exclude_authrole: [string]
  1782. exclude_authrole = self.exclude_authrole
  1783. if exclude_authid:
  1784. _exclude_authrole = []
  1785. for authrole in exclude_authrole:
  1786. _exclude_authrole.append(builder.CreateString(authrole))
  1787. message_fbs.PublishGen.PublishStartExcludeAuthroleVector(builder, len(_exclude_authrole))
  1788. for o in reversed(_exclude_authrole):
  1789. builder.PrependUOffsetTRelative(o)
  1790. exclude_authrole = builder.EndVector(len(_exclude_authrole))
  1791. # eligible: [int]
  1792. eligible = self.eligible
  1793. if eligible:
  1794. message_fbs.PublishGen.PublishStartEligibleAuthidVector(builder, len(eligible))
  1795. for session in reversed(eligible):
  1796. builder.PrependUint64(session)
  1797. eligible = builder.EndVector(len(eligible))
  1798. # eligible_authid: [string]
  1799. eligible_authid = self.eligible_authid
  1800. if eligible_authid:
  1801. _eligible_authid = []
  1802. for authid in eligible_authid:
  1803. _eligible_authid.append(builder.CreateString(authid))
  1804. message_fbs.PublishGen.PublishStartEligibleAuthidVector(builder, len(_eligible_authid))
  1805. for o in reversed(_eligible_authid):
  1806. builder.PrependUOffsetTRelative(o)
  1807. eligible_authid = builder.EndVector(len(_eligible_authid))
  1808. # eligible_authrole: [string]
  1809. eligible_authrole = self.eligible_authrole
  1810. if eligible_authrole:
  1811. _eligible_authrole = []
  1812. for authrole in eligible_authrole:
  1813. _eligible_authrole.append(builder.CreateString(authrole))
  1814. message_fbs.PublishGen.PublishStartEligibleAuthroleVector(builder, len(_eligible_authrole))
  1815. for o in reversed(_eligible_authrole):
  1816. builder.PrependUOffsetTRelative(o)
  1817. eligible_authrole = builder.EndVector(len(_eligible_authrole))
  1818. # now start and build a new object ..
  1819. message_fbs.PublishGen.PublishStart(builder)
  1820. if self.request is not None:
  1821. message_fbs.PublishGen.PublishAddRequest(builder, self.request)
  1822. if topic:
  1823. message_fbs.PublishGen.PublishAddTopic(builder, topic)
  1824. if args:
  1825. message_fbs.PublishGen.PublishAddArgs(builder, args)
  1826. if kwargs:
  1827. message_fbs.PublishGen.PublishAddKwargs(builder, kwargs)
  1828. if payload:
  1829. message_fbs.PublishGen.PublishAddPayload(builder, payload)
  1830. if self.acknowledge is not None:
  1831. message_fbs.PublishGen.PublishAddAcknowledge(builder, self.acknowledge)
  1832. if self.retain is not None:
  1833. message_fbs.PublishGen.PublishAddRetain(builder, self.retain)
  1834. if self.exclude_me is not None:
  1835. message_fbs.PublishGen.PublishAddExcludeMe(builder, self.exclude_me)
  1836. if exclude:
  1837. message_fbs.PublishGen.PublishAddExclude(builder, exclude)
  1838. if exclude_authid:
  1839. message_fbs.PublishGen.PublishAddExcludeAuthid(builder, exclude_authid)
  1840. if exclude_authrole:
  1841. message_fbs.PublishGen.PublishAddExcludeAuthrole(builder, exclude_authrole)
  1842. if eligible:
  1843. message_fbs.PublishGen.PublishAddEligible(builder, eligible)
  1844. if eligible_authid:
  1845. message_fbs.PublishGen.PublishAddEligibleAuthid(builder, eligible_authid)
  1846. if eligible_authrole:
  1847. message_fbs.PublishGen.PublishAddEligibleAuthrole(builder, eligible_authrole)
  1848. if self.enc_algo:
  1849. message_fbs.PublishGen.PublishAddEncAlgo(builder, self.enc_algo)
  1850. if enc_key:
  1851. message_fbs.PublishGen.PublishAddEncKey(builder, enc_key)
  1852. if self.enc_serializer:
  1853. message_fbs.PublishGen.PublishAddEncSerializer(builder, self.enc_serializer)
  1854. # FIXME: add forward_for
  1855. msg = message_fbs.PublishGen.PublishEnd(builder)
  1856. message_fbs.Message.MessageStart(builder)
  1857. message_fbs.Message.MessageAddMsgType(builder, message_fbs.MessageType.PUBLISH)
  1858. message_fbs.Message.MessageAddMsg(builder, msg)
  1859. union_msg = message_fbs.Message.MessageEnd(builder)
  1860. return union_msg
  1861. @staticmethod
  1862. def parse(wmsg):
  1863. """
  1864. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  1865. :param wmsg: The unserialized raw message.
  1866. :type wmsg: list
  1867. :returns: An instance of this class.
  1868. """
  1869. # this should already be verified by WampSerializer.unserialize
  1870. assert(len(wmsg) > 0 and wmsg[0] == Publish.MESSAGE_TYPE)
  1871. if len(wmsg) not in (4, 5, 6):
  1872. raise ProtocolError("invalid message length {0} for PUBLISH".format(len(wmsg)))
  1873. request = check_or_raise_id(wmsg[1], u"'request' in PUBLISH")
  1874. options = check_or_raise_extra(wmsg[2], u"'options' in PUBLISH")
  1875. topic = check_or_raise_uri(wmsg[3], u"'topic' in PUBLISH")
  1876. args = None
  1877. kwargs = None
  1878. payload = None
  1879. if len(wmsg) == 5 and type(wmsg[4]) in [six.text_type, six.binary_type]:
  1880. payload = wmsg[4]
  1881. enc_algo = options.get(u'enc_algo', None)
  1882. if enc_algo and not is_valid_enc_algo(enc_algo):
  1883. raise ProtocolError("invalid value {0} for 'enc_algo' option in PUBLISH".format(enc_algo))
  1884. enc_key = options.get(u'enc_key', None)
  1885. if enc_key and type(enc_key) != six.text_type:
  1886. raise ProtocolError("invalid type {0} for 'enc_key' option in PUBLISH".format(type(enc_key)))
  1887. enc_serializer = options.get(u'enc_serializer', None)
  1888. if enc_serializer and not is_valid_enc_serializer(enc_serializer):
  1889. raise ProtocolError("invalid value {0} for 'enc_serializer' option in PUBLISH".format(enc_serializer))
  1890. else:
  1891. if len(wmsg) > 4:
  1892. args = wmsg[4]
  1893. if type(args) not in [list, six.text_type, six.binary_type]:
  1894. raise ProtocolError("invalid type {0} for 'args' in PUBLISH".format(type(args)))
  1895. if len(wmsg) > 5:
  1896. kwargs = wmsg[5]
  1897. if type(kwargs) not in [dict, six.text_type, six.binary_type]:
  1898. raise ProtocolError("invalid type {0} for 'kwargs' in PUBLISH".format(type(kwargs)))
  1899. enc_algo = None
  1900. enc_key = None
  1901. enc_serializer = None
  1902. acknowledge = None
  1903. exclude_me = None
  1904. exclude = None
  1905. exclude_authid = None
  1906. exclude_authrole = None
  1907. eligible = None
  1908. eligible_authid = None
  1909. eligible_authrole = None
  1910. retain = None
  1911. forward_for = None
  1912. if u'acknowledge' in options:
  1913. option_acknowledge = options[u'acknowledge']
  1914. if type(option_acknowledge) != bool:
  1915. raise ProtocolError("invalid type {0} for 'acknowledge' option in PUBLISH".format(type(option_acknowledge)))
  1916. acknowledge = option_acknowledge
  1917. if u'exclude_me' in options:
  1918. option_exclude_me = options[u'exclude_me']
  1919. if type(option_exclude_me) != bool:
  1920. raise ProtocolError("invalid type {0} for 'exclude_me' option in PUBLISH".format(type(option_exclude_me)))
  1921. exclude_me = option_exclude_me
  1922. if u'exclude' in options:
  1923. option_exclude = options[u'exclude']
  1924. if type(option_exclude) != list:
  1925. raise ProtocolError("invalid type {0} for 'exclude' option in PUBLISH".format(type(option_exclude)))
  1926. for _sessionid in option_exclude:
  1927. if type(_sessionid) not in six.integer_types:
  1928. raise ProtocolError("invalid type {0} for value in 'exclude' option in PUBLISH".format(type(_sessionid)))
  1929. exclude = option_exclude
  1930. if u'exclude_authid' in options:
  1931. option_exclude_authid = options[u'exclude_authid']
  1932. if type(option_exclude_authid) != list:
  1933. raise ProtocolError("invalid type {0} for 'exclude_authid' option in PUBLISH".format(type(option_exclude_authid)))
  1934. for _authid in option_exclude_authid:
  1935. if type(_authid) != six.text_type:
  1936. raise ProtocolError("invalid type {0} for value in 'exclude_authid' option in PUBLISH".format(type(_authid)))
  1937. exclude_authid = option_exclude_authid
  1938. if u'exclude_authrole' in options:
  1939. option_exclude_authrole = options[u'exclude_authrole']
  1940. if type(option_exclude_authrole) != list:
  1941. raise ProtocolError("invalid type {0} for 'exclude_authrole' option in PUBLISH".format(type(option_exclude_authrole)))
  1942. for _authrole in option_exclude_authrole:
  1943. if type(_authrole) != six.text_type:
  1944. raise ProtocolError("invalid type {0} for value in 'exclude_authrole' option in PUBLISH".format(type(_authrole)))
  1945. exclude_authrole = option_exclude_authrole
  1946. if u'eligible' in options:
  1947. option_eligible = options[u'eligible']
  1948. if type(option_eligible) != list:
  1949. raise ProtocolError("invalid type {0} for 'eligible' option in PUBLISH".format(type(option_eligible)))
  1950. for sessionId in option_eligible:
  1951. if type(sessionId) not in six.integer_types:
  1952. raise ProtocolError("invalid type {0} for value in 'eligible' option in PUBLISH".format(type(sessionId)))
  1953. eligible = option_eligible
  1954. if u'eligible_authid' in options:
  1955. option_eligible_authid = options[u'eligible_authid']
  1956. if type(option_eligible_authid) != list:
  1957. raise ProtocolError("invalid type {0} for 'eligible_authid' option in PUBLISH".format(type(option_eligible_authid)))
  1958. for _authid in option_eligible_authid:
  1959. if type(_authid) != six.text_type:
  1960. raise ProtocolError("invalid type {0} for value in 'eligible_authid' option in PUBLISH".format(type(_authid)))
  1961. eligible_authid = option_eligible_authid
  1962. if u'eligible_authrole' in options:
  1963. option_eligible_authrole = options[u'eligible_authrole']
  1964. if type(option_eligible_authrole) != list:
  1965. raise ProtocolError("invalid type {0} for 'eligible_authrole' option in PUBLISH".format(type(option_eligible_authrole)))
  1966. for _authrole in option_eligible_authrole:
  1967. if type(_authrole) != six.text_type:
  1968. raise ProtocolError("invalid type {0} for value in 'eligible_authrole' option in PUBLISH".format(type(_authrole)))
  1969. eligible_authrole = option_eligible_authrole
  1970. if u'retain' in options:
  1971. retain = options[u'retain']
  1972. if type(retain) != bool:
  1973. raise ProtocolError("invalid type {0} for 'retain' option in PUBLISH".format(type(retain)))
  1974. if u'forward_for' in options:
  1975. forward_for = options[u'forward_for']
  1976. valid = False
  1977. if type(forward_for) == list:
  1978. for ff in forward_for:
  1979. if type(ff) != dict:
  1980. break
  1981. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  1982. break
  1983. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  1984. break
  1985. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  1986. break
  1987. valid = True
  1988. if not valid:
  1989. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in PUBLISH")
  1990. obj = Publish(request,
  1991. topic,
  1992. args=args,
  1993. kwargs=kwargs,
  1994. payload=payload,
  1995. acknowledge=acknowledge,
  1996. exclude_me=exclude_me,
  1997. exclude=exclude,
  1998. exclude_authid=exclude_authid,
  1999. exclude_authrole=exclude_authrole,
  2000. eligible=eligible,
  2001. eligible_authid=eligible_authid,
  2002. eligible_authrole=eligible_authrole,
  2003. retain=retain,
  2004. enc_algo=enc_algo,
  2005. enc_key=enc_key,
  2006. enc_serializer=enc_serializer,
  2007. forward_for=forward_for)
  2008. return obj
  2009. def marshal_options(self):
  2010. options = {}
  2011. if self.acknowledge is not None:
  2012. options[u'acknowledge'] = self.acknowledge
  2013. if self.exclude_me is not None:
  2014. options[u'exclude_me'] = self.exclude_me
  2015. if self.exclude is not None:
  2016. options[u'exclude'] = self.exclude
  2017. if self.exclude_authid is not None:
  2018. options[u'exclude_authid'] = self.exclude_authid
  2019. if self.exclude_authrole is not None:
  2020. options[u'exclude_authrole'] = self.exclude_authrole
  2021. if self.eligible is not None:
  2022. options[u'eligible'] = self.eligible
  2023. if self.eligible_authid is not None:
  2024. options[u'eligible_authid'] = self.eligible_authid
  2025. if self.eligible_authrole is not None:
  2026. options[u'eligible_authrole'] = self.eligible_authrole
  2027. if self.retain is not None:
  2028. options[u'retain'] = self.retain
  2029. if self.payload:
  2030. if self.enc_algo is not None:
  2031. options[u'enc_algo'] = self.enc_algo
  2032. if self.enc_key is not None:
  2033. options[u'enc_key'] = self.enc_key
  2034. if self.enc_serializer is not None:
  2035. options[u'enc_serializer'] = self.enc_serializer
  2036. if self.forward_for is not None:
  2037. options[u'forward_for'] = self.forward_for
  2038. return options
  2039. def marshal(self):
  2040. """
  2041. Marshal this object into a raw message for subsequent serialization to bytes.
  2042. :returns: The serialized raw message.
  2043. :rtype: list
  2044. """
  2045. options = self.marshal_options()
  2046. if self.payload:
  2047. return [Publish.MESSAGE_TYPE, self.request, options, self.topic, self.payload]
  2048. else:
  2049. if self.kwargs:
  2050. return [Publish.MESSAGE_TYPE, self.request, options, self.topic, self.args, self.kwargs]
  2051. elif self.args:
  2052. return [Publish.MESSAGE_TYPE, self.request, options, self.topic, self.args]
  2053. else:
  2054. return [Publish.MESSAGE_TYPE, self.request, options, self.topic]
  2055. def __str__(self):
  2056. """
  2057. Returns string representation of this message.
  2058. """
  2059. return u"Publish(request={}, topic={}, args={}, kwargs={}, acknowledge={}, exclude_me={}, exclude={}, exclude_authid={}, exclude_authrole={}, eligible={}, eligible_authid={}, eligible_authrole={}, retain={}, enc_algo={}, enc_key={}, enc_serializer={}, payload={}, forward_for={})".format(self.request, self.topic, self.args, self.kwargs, self.acknowledge, self.exclude_me, self.exclude, self.exclude_authid, self.exclude_authrole, self.eligible, self.eligible_authid, self.eligible_authrole, self.retain, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), self.forward_for)
  2060. class Published(Message):
  2061. """
  2062. A WAMP ``PUBLISHED`` message.
  2063. Format: ``[PUBLISHED, PUBLISH.Request|id, Publication|id]``
  2064. """
  2065. MESSAGE_TYPE = 17
  2066. """
  2067. The WAMP message code for this type of message.
  2068. """
  2069. __slots__ = (
  2070. 'request',
  2071. 'publication',
  2072. )
  2073. def __init__(self, request, publication):
  2074. """
  2075. :param request: The request ID of the original `PUBLISH` request.
  2076. :type request: int
  2077. :param publication: The publication ID for the published event.
  2078. :type publication: int
  2079. """
  2080. assert(type(request) in six.integer_types)
  2081. assert(type(publication) in six.integer_types)
  2082. Message.__init__(self)
  2083. self.request = request
  2084. self.publication = publication
  2085. @staticmethod
  2086. def parse(wmsg):
  2087. """
  2088. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  2089. :param wmsg: The unserialized raw message.
  2090. :type wmsg: list
  2091. :returns: An instance of this class.
  2092. """
  2093. # this should already be verified by WampSerializer.unserialize
  2094. assert(len(wmsg) > 0 and wmsg[0] == Published.MESSAGE_TYPE)
  2095. if len(wmsg) != 3:
  2096. raise ProtocolError("invalid message length {0} for PUBLISHED".format(len(wmsg)))
  2097. request = check_or_raise_id(wmsg[1], u"'request' in PUBLISHED")
  2098. publication = check_or_raise_id(wmsg[2], u"'publication' in PUBLISHED")
  2099. obj = Published(request, publication)
  2100. return obj
  2101. def marshal(self):
  2102. """
  2103. Marshal this object into a raw message for subsequent serialization to bytes.
  2104. :returns: The serialized raw message.
  2105. :rtype: list
  2106. """
  2107. return [Published.MESSAGE_TYPE, self.request, self.publication]
  2108. def __str__(self):
  2109. """
  2110. Returns string representation of this message.
  2111. """
  2112. return u"Published(request={0}, publication={1})".format(self.request, self.publication)
  2113. class Subscribe(Message):
  2114. """
  2115. A WAMP ``SUBSCRIBE`` message.
  2116. Format: ``[SUBSCRIBE, Request|id, Options|dict, Topic|uri]``
  2117. """
  2118. MESSAGE_TYPE = 32
  2119. """
  2120. The WAMP message code for this type of message.
  2121. """
  2122. MATCH_EXACT = u'exact'
  2123. MATCH_PREFIX = u'prefix'
  2124. MATCH_WILDCARD = u'wildcard'
  2125. __slots__ = (
  2126. 'request',
  2127. 'topic',
  2128. 'match',
  2129. 'get_retained',
  2130. 'forward_for',
  2131. )
  2132. def __init__(self,
  2133. request,
  2134. topic,
  2135. match=None,
  2136. get_retained=None,
  2137. forward_for=None):
  2138. """
  2139. :param request: The WAMP request ID of this request.
  2140. :type request: int
  2141. :param topic: The WAMP or application URI of the PubSub topic to subscribe to.
  2142. :type topic: str
  2143. :param match: The topic matching method to be used for the subscription.
  2144. :type match: str
  2145. :param get_retained: Whether the client wants the retained message we may have along with the subscription.
  2146. :type get_retained: bool or None
  2147. :param forward_for: When this Subscribe is forwarded over a router-to-router link,
  2148. or via an intermediary router.
  2149. :type forward_for: list[dict]
  2150. """
  2151. assert(type(request) in six.integer_types)
  2152. assert(type(topic) == six.text_type)
  2153. assert(match is None or type(match) == six.text_type)
  2154. assert(match is None or match in [Subscribe.MATCH_EXACT, Subscribe.MATCH_PREFIX, Subscribe.MATCH_WILDCARD])
  2155. assert(get_retained is None or type(get_retained) is bool)
  2156. assert(forward_for is None or type(forward_for) == list)
  2157. if forward_for:
  2158. for ff in forward_for:
  2159. assert type(ff) == dict
  2160. assert 'session' in ff and type(ff['session']) in six.integer_types
  2161. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  2162. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  2163. Message.__init__(self)
  2164. self.request = request
  2165. self.topic = topic
  2166. self.match = match or Subscribe.MATCH_EXACT
  2167. self.get_retained = get_retained
  2168. self.forward_for = forward_for
  2169. @staticmethod
  2170. def parse(wmsg):
  2171. """
  2172. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  2173. :param wmsg: The unserialized raw message.
  2174. :type wmsg: list
  2175. :returns: An instance of this class.
  2176. """
  2177. # this should already be verified by WampSerializer.unserialize
  2178. assert(len(wmsg) > 0 and wmsg[0] == Subscribe.MESSAGE_TYPE)
  2179. if len(wmsg) != 4:
  2180. raise ProtocolError("invalid message length {0} for SUBSCRIBE".format(len(wmsg)))
  2181. request = check_or_raise_id(wmsg[1], u"'request' in SUBSCRIBE")
  2182. options = check_or_raise_extra(wmsg[2], u"'options' in SUBSCRIBE")
  2183. topic = check_or_raise_uri(wmsg[3], u"'topic' in SUBSCRIBE", allow_empty_components=True)
  2184. match = Subscribe.MATCH_EXACT
  2185. get_retained = None
  2186. forward_for = None
  2187. if u'match' in options:
  2188. option_match = options[u'match']
  2189. if type(option_match) != six.text_type:
  2190. raise ProtocolError("invalid type {0} for 'match' option in SUBSCRIBE".format(type(option_match)))
  2191. if option_match not in [Subscribe.MATCH_EXACT, Subscribe.MATCH_PREFIX, Subscribe.MATCH_WILDCARD]:
  2192. raise ProtocolError("invalid value {0} for 'match' option in SUBSCRIBE".format(option_match))
  2193. match = option_match
  2194. if u'get_retained' in options:
  2195. get_retained = options[u'get_retained']
  2196. if type(get_retained) != bool:
  2197. raise ProtocolError("invalid type {0} for 'get_retained' option in SUBSCRIBE".format(type(get_retained)))
  2198. if u'forward_for' in options:
  2199. forward_for = options[u'forward_for']
  2200. valid = False
  2201. if type(forward_for) == list:
  2202. for ff in forward_for:
  2203. if type(ff) != dict:
  2204. break
  2205. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  2206. break
  2207. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  2208. break
  2209. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  2210. break
  2211. valid = True
  2212. if not valid:
  2213. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in SUBSCRIBE")
  2214. obj = Subscribe(request, topic, match=match, get_retained=get_retained, forward_for=forward_for)
  2215. return obj
  2216. def marshal_options(self):
  2217. options = {}
  2218. if self.match and self.match != Subscribe.MATCH_EXACT:
  2219. options[u'match'] = self.match
  2220. if self.get_retained is not None:
  2221. options[u'get_retained'] = self.get_retained
  2222. if self.forward_for is not None:
  2223. options[u'forward_for'] = self.forward_for
  2224. return options
  2225. def marshal(self):
  2226. """
  2227. Marshal this object into a raw message for subsequent serialization to bytes.
  2228. :returns: The serialized raw message.
  2229. :rtype: list
  2230. """
  2231. return [Subscribe.MESSAGE_TYPE, self.request, self.marshal_options(), self.topic]
  2232. def __str__(self):
  2233. """
  2234. Returns string representation of this message.
  2235. """
  2236. return u"Subscribe(request={0}, topic={1}, match={2}, get_retained={3}, forward_for={4})".format(self.request, self.topic, self.match, self.get_retained, self.forward_for)
  2237. class Subscribed(Message):
  2238. """
  2239. A WAMP ``SUBSCRIBED`` message.
  2240. Format: ``[SUBSCRIBED, SUBSCRIBE.Request|id, Subscription|id]``
  2241. """
  2242. MESSAGE_TYPE = 33
  2243. """
  2244. The WAMP message code for this type of message.
  2245. """
  2246. __slots__ = (
  2247. 'request',
  2248. 'subscription',
  2249. )
  2250. def __init__(self, request, subscription):
  2251. """
  2252. :param request: The request ID of the original ``SUBSCRIBE`` request.
  2253. :type request: int
  2254. :param subscription: The subscription ID for the subscribed topic (or topic pattern).
  2255. :type subscription: int
  2256. """
  2257. assert(type(request) in six.integer_types)
  2258. assert(type(subscription) in six.integer_types)
  2259. Message.__init__(self)
  2260. self.request = request
  2261. self.subscription = subscription
  2262. @staticmethod
  2263. def parse(wmsg):
  2264. """
  2265. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  2266. :param wmsg: The unserialized raw message.
  2267. :type wmsg: list
  2268. :returns: An instance of this class.
  2269. """
  2270. # this should already be verified by WampSerializer.unserialize
  2271. assert(len(wmsg) > 0 and wmsg[0] == Subscribed.MESSAGE_TYPE)
  2272. if len(wmsg) != 3:
  2273. raise ProtocolError("invalid message length {0} for SUBSCRIBED".format(len(wmsg)))
  2274. request = check_or_raise_id(wmsg[1], u"'request' in SUBSCRIBED")
  2275. subscription = check_or_raise_id(wmsg[2], u"'subscription' in SUBSCRIBED")
  2276. obj = Subscribed(request, subscription)
  2277. return obj
  2278. def marshal(self):
  2279. """
  2280. Marshal this object into a raw message for subsequent serialization to bytes.
  2281. :returns: The serialized raw message.
  2282. :rtype: list
  2283. """
  2284. return [Subscribed.MESSAGE_TYPE, self.request, self.subscription]
  2285. def __str__(self):
  2286. """
  2287. Returns string representation of this message.
  2288. """
  2289. return u"Subscribed(request={0}, subscription={1})".format(self.request, self.subscription)
  2290. class Unsubscribe(Message):
  2291. """
  2292. A WAMP ``UNSUBSCRIBE`` message.
  2293. Formats:
  2294. * ``[UNSUBSCRIBE, Request|id, SUBSCRIBED.Subscription|id]``
  2295. * ``[UNSUBSCRIBE, Request|id, SUBSCRIBED.Subscription|id, Options|dict]``
  2296. """
  2297. MESSAGE_TYPE = 34
  2298. """
  2299. The WAMP message code for this type of message.
  2300. """
  2301. __slots__ = (
  2302. 'request',
  2303. 'subscription',
  2304. 'forward_for',
  2305. )
  2306. def __init__(self, request, subscription, forward_for=None):
  2307. """
  2308. :param request: The WAMP request ID of this request.
  2309. :type request: int
  2310. :param subscription: The subscription ID for the subscription to unsubscribe from.
  2311. :type subscription: int
  2312. :param forward_for: When this Unsubscribe is forwarded over a router-to-router link,
  2313. or via an intermediary router.
  2314. :type forward_for: list[dict]
  2315. """
  2316. assert(type(request) in six.integer_types)
  2317. assert(type(subscription) in six.integer_types)
  2318. if forward_for:
  2319. for ff in forward_for:
  2320. assert type(ff) == dict
  2321. assert 'session' in ff and type(ff['session']) in six.integer_types
  2322. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  2323. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  2324. Message.__init__(self)
  2325. self.request = request
  2326. self.subscription = subscription
  2327. self.forward_for = forward_for
  2328. @staticmethod
  2329. def parse(wmsg):
  2330. """
  2331. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  2332. :param wmsg: The unserialized raw message.
  2333. :type wmsg: list
  2334. :returns: An instance of this class.
  2335. """
  2336. # this should already be verified by WampSerializer.unserialize
  2337. assert(len(wmsg) > 0 and wmsg[0] == Unsubscribe.MESSAGE_TYPE)
  2338. if len(wmsg) not in [3, 4]:
  2339. raise ProtocolError("invalid message length {0} for WAMP UNSUBSCRIBE".format(len(wmsg)))
  2340. request = check_or_raise_id(wmsg[1], u"'request' in UNSUBSCRIBE")
  2341. subscription = check_or_raise_id(wmsg[2], u"'subscription' in UNSUBSCRIBE")
  2342. options = None
  2343. if len(wmsg) > 3:
  2344. options = check_or_raise_extra(wmsg[3], u"'options' in UNSUBSCRIBE")
  2345. forward_for = None
  2346. if options and u'forward_for' in options:
  2347. forward_for = options[u'forward_for']
  2348. valid = False
  2349. if type(forward_for) == list:
  2350. for ff in forward_for:
  2351. if type(ff) != dict:
  2352. break
  2353. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  2354. break
  2355. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  2356. break
  2357. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  2358. break
  2359. valid = True
  2360. if not valid:
  2361. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in UNSUBSCRIBE")
  2362. obj = Unsubscribe(request, subscription, forward_for=forward_for)
  2363. return obj
  2364. def marshal(self):
  2365. """
  2366. Marshal this object into a raw message for subsequent serialization to bytes.
  2367. :returns: The serialized raw message.
  2368. :rtype: list
  2369. """
  2370. if self.forward_for:
  2371. options = {
  2372. u'forward_for': self.forward_for,
  2373. }
  2374. return [Unsubscribe.MESSAGE_TYPE, self.request, self.subscription, options]
  2375. else:
  2376. return [Unsubscribe.MESSAGE_TYPE, self.request, self.subscription]
  2377. def __str__(self):
  2378. """
  2379. Returns string representation of this message.
  2380. """
  2381. return u"Unsubscribe(request={0}, subscription={1}, forward_for={2})".format(self.request, self.subscription, self.forward_for)
  2382. class Unsubscribed(Message):
  2383. """
  2384. A WAMP ``UNSUBSCRIBED`` message.
  2385. Formats:
  2386. * ``[UNSUBSCRIBED, UNSUBSCRIBE.Request|id]``
  2387. * ``[UNSUBSCRIBED, UNSUBSCRIBE.Request|id, Details|dict]``
  2388. """
  2389. MESSAGE_TYPE = 35
  2390. """
  2391. The WAMP message code for this type of message.
  2392. """
  2393. __slots__ = (
  2394. 'request',
  2395. 'subscription',
  2396. 'reason',
  2397. )
  2398. def __init__(self, request, subscription=None, reason=None):
  2399. """
  2400. :param request: The request ID of the original ``UNSUBSCRIBE`` request or
  2401. ``0`` is router triggered unsubscribe ("router revocation signaling").
  2402. :type request: int
  2403. :param subscription: If unsubscribe was actively triggered by router, the ID
  2404. of the subscription revoked.
  2405. :type subscription: int or None
  2406. :param reason: The reason (an URI) for an active (router initiated) revocation.
  2407. :type reason: str or None.
  2408. """
  2409. assert(type(request) in six.integer_types)
  2410. assert(subscription is None or type(subscription) in six.integer_types)
  2411. assert(reason is None or type(reason) == six.text_type)
  2412. assert((request != 0 and subscription is None) or (request == 0 and subscription != 0))
  2413. Message.__init__(self)
  2414. self.request = request
  2415. self.subscription = subscription
  2416. self.reason = reason
  2417. @staticmethod
  2418. def parse(wmsg):
  2419. """
  2420. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  2421. :param wmsg: The unserialized raw message.
  2422. :type wmsg: list
  2423. :returns: An instance of this class.
  2424. """
  2425. # this should already be verified by WampSerializer.unserialize
  2426. assert(len(wmsg) > 0 and wmsg[0] == Unsubscribed.MESSAGE_TYPE)
  2427. if len(wmsg) not in [2, 3]:
  2428. raise ProtocolError("invalid message length {0} for UNSUBSCRIBED".format(len(wmsg)))
  2429. request = check_or_raise_id(wmsg[1], u"'request' in UNSUBSCRIBED")
  2430. subscription = None
  2431. reason = None
  2432. if len(wmsg) > 2:
  2433. details = check_or_raise_extra(wmsg[2], u"'details' in UNSUBSCRIBED")
  2434. if u"subscription" in details:
  2435. details_subscription = details[u"subscription"]
  2436. if type(details_subscription) not in six.integer_types:
  2437. raise ProtocolError("invalid type {0} for 'subscription' detail in UNSUBSCRIBED".format(type(details_subscription)))
  2438. subscription = details_subscription
  2439. if u"reason" in details:
  2440. reason = check_or_raise_uri(details[u"reason"], u"'reason' in UNSUBSCRIBED")
  2441. obj = Unsubscribed(request, subscription, reason)
  2442. return obj
  2443. def marshal(self):
  2444. """
  2445. Marshal this object into a raw message for subsequent serialization to bytes.
  2446. :returns: The serialized raw message.
  2447. :rtype: list
  2448. """
  2449. if self.reason is not None or self.subscription is not None:
  2450. details = {}
  2451. if self.reason is not None:
  2452. details[u"reason"] = self.reason
  2453. if self.subscription is not None:
  2454. details[u"subscription"] = self.subscription
  2455. return [Unsubscribed.MESSAGE_TYPE, self.request, details]
  2456. else:
  2457. return [Unsubscribed.MESSAGE_TYPE, self.request]
  2458. def __str__(self):
  2459. """
  2460. Returns string representation of this message.
  2461. """
  2462. return u"Unsubscribed(request={0}, reason={1}, subscription={2})".format(self.request, self.reason, self.subscription)
  2463. class Event(Message):
  2464. """
  2465. A WAMP ``EVENT`` message.
  2466. Formats:
  2467. * ``[EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id, Details|dict]``
  2468. * ``[EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id, Details|dict, PUBLISH.Arguments|list]``
  2469. * ``[EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id, Details|dict, PUBLISH.Arguments|list, PUBLISH.ArgumentsKw|dict]``
  2470. * ``[EVENT, SUBSCRIBED.Subscription|id, PUBLISHED.Publication|id, Details|dict, PUBLISH.Payload|binary]``
  2471. """
  2472. MESSAGE_TYPE = 36
  2473. """
  2474. The WAMP message code for this type of message.
  2475. """
  2476. __slots__ = (
  2477. # uint64
  2478. '_subscription',
  2479. # uint64
  2480. '_publication',
  2481. # [uint8]
  2482. '_args',
  2483. # [uint8]
  2484. '_kwargs',
  2485. # [uint8]
  2486. '_payload',
  2487. # Payload => uint8
  2488. '_enc_algo',
  2489. # Serializer => uint8
  2490. '_enc_serializer',
  2491. # [uint8]
  2492. '_enc_key',
  2493. # uint64
  2494. '_publisher',
  2495. # string (principal)
  2496. '_publisher_authid',
  2497. # string (principal)
  2498. '_publisher_authrole',
  2499. # string (uri)
  2500. '_topic',
  2501. # bool
  2502. '_retained',
  2503. # bool - FIXME: rename to "acknowledge"
  2504. '_x_acknowledged_delivery',
  2505. # [Principal]
  2506. '_forward_for',
  2507. )
  2508. def __init__(self, subscription=None, publication=None, args=None, kwargs=None, payload=None,
  2509. publisher=None, publisher_authid=None, publisher_authrole=None, topic=None,
  2510. retained=None, x_acknowledged_delivery=None,
  2511. enc_algo=None, enc_key=None, enc_serializer=None, forward_for=None,
  2512. from_fbs=None):
  2513. """
  2514. :param subscription: The subscription ID this event is dispatched under.
  2515. :type subscription: int
  2516. :param publication: The publication ID of the dispatched event.
  2517. :type publication: int
  2518. :param args: Positional values for application-defined exception.
  2519. Must be serializable using any serializers in use.
  2520. :type args: list or tuple or None
  2521. :param kwargs: Keyword values for application-defined exception.
  2522. Must be serializable using any serializers in use.
  2523. :type kwargs: dict or None
  2524. :param payload: Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
  2525. :type payload: bytes or None
  2526. :param publisher: The WAMP session ID of the publisher. Only filled if publisher is disclosed.
  2527. :type publisher: None or int
  2528. :param publisher_authid: The WAMP authid of the publisher. Only filled if publisher is disclosed.
  2529. :type publisher_authid: None or unicode
  2530. :param publisher_authrole: The WAMP authrole of the publisher. Only filled if publisher is disclosed.
  2531. :type publisher_authrole: None or unicode
  2532. :param topic: For pattern-based subscriptions, the event MUST contain the actual topic published to.
  2533. :type topic: str or None
  2534. :param retained: Whether the message was retained by the broker on the topic, rather than just published.
  2535. :type retained: bool or None
  2536. :param x_acknowledged_delivery: Whether this Event should be acknowledged.
  2537. :type x_acknowledged_delivery: bool or None
  2538. :param enc_algo: If using payload transparency, the encoding algorithm that was used to encode the payload.
  2539. :type enc_algo: str or None
  2540. :param enc_key: If using payload transparency with an encryption algorithm, the payload encryption key.
  2541. :type enc_key: str or None
  2542. :param enc_serializer: If using payload transparency, the payload object serializer that was used encoding the payload.
  2543. :type enc_serializer: str or None
  2544. :param forward_for: When this Event is forwarded for a client (or from an intermediary router).
  2545. :type forward_for: list[dict]
  2546. """
  2547. assert(subscription is None or type(subscription) in six.integer_types)
  2548. assert(publication is None or type(publication) in six.integer_types)
  2549. assert(args is None or type(args) in [list, tuple])
  2550. assert(kwargs is None or type(kwargs) == dict)
  2551. assert(payload is None or type(payload) == six.binary_type)
  2552. assert(payload is None or (payload is not None and args is None and kwargs is None))
  2553. assert(publisher is None or type(publisher) in six.integer_types)
  2554. assert(publisher_authid is None or type(publisher_authid) == six.text_type)
  2555. assert(publisher_authrole is None or type(publisher_authrole) == six.text_type)
  2556. assert(topic is None or type(topic) == six.text_type)
  2557. assert(retained is None or type(retained) == bool)
  2558. assert(x_acknowledged_delivery is None or type(x_acknowledged_delivery) == bool)
  2559. assert(enc_algo is None or is_valid_enc_algo(enc_algo))
  2560. assert((enc_algo is None and enc_key is None and enc_serializer is None) or (payload is not None and enc_algo is not None))
  2561. assert(enc_key is None or type(enc_key) == six.text_type)
  2562. assert(enc_serializer is None or is_valid_enc_serializer(enc_serializer))
  2563. assert(forward_for is None or type(forward_for) == list)
  2564. if forward_for:
  2565. for ff in forward_for:
  2566. assert type(ff) == dict
  2567. assert 'session' in ff and type(ff['session']) in six.integer_types
  2568. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  2569. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  2570. Message.__init__(self, from_fbs=from_fbs)
  2571. self._subscription = subscription
  2572. self._publication = publication
  2573. self._args = args
  2574. self._kwargs = _validate_kwargs(kwargs)
  2575. self._payload = payload
  2576. self._publisher = publisher
  2577. self._publisher_authid = publisher_authid
  2578. self._publisher_authrole = publisher_authrole
  2579. self._topic = topic
  2580. self._retained = retained
  2581. self._x_acknowledged_delivery = x_acknowledged_delivery
  2582. self._enc_algo = enc_algo
  2583. self._enc_key = enc_key
  2584. self._enc_serializer = enc_serializer
  2585. self._forward_for = forward_for
  2586. def __eq__(self, other):
  2587. if not isinstance(other, self.__class__):
  2588. return False
  2589. if not Message.__eq__(self, other):
  2590. return False
  2591. if other.subscription != self.subscription:
  2592. return False
  2593. if other.publication != self.publication:
  2594. return False
  2595. if other.args != self.args:
  2596. return False
  2597. if other.kwargs != self.kwargs:
  2598. return False
  2599. if other.payload != self.payload:
  2600. return False
  2601. if other.publisher != self.publisher:
  2602. return False
  2603. if other.publisher_authid != self.publisher_authid:
  2604. return False
  2605. if other.publisher_authrole != self.publisher_authrole:
  2606. return False
  2607. if other.topic != self.topic:
  2608. return False
  2609. if other.retained != self.retained:
  2610. return False
  2611. if other.x_acknowledged_delivery != self.x_acknowledged_delivery:
  2612. return False
  2613. if other.enc_algo != self.enc_algo:
  2614. return False
  2615. if other.enc_key != self.enc_key:
  2616. return False
  2617. if other.enc_serializer != self.enc_serializer:
  2618. return False
  2619. if other.forward_for != self.forward_for:
  2620. return False
  2621. return True
  2622. def __ne__(self, other):
  2623. return not self.__eq__(other)
  2624. @property
  2625. def subscription(self):
  2626. if self._subscription is None and self._from_fbs:
  2627. self._subscription = self._from_fbs.Subscription()
  2628. return self._subscription
  2629. @subscription.setter
  2630. def subscription(self, value):
  2631. assert(value is None or type(value) in six.integer_types)
  2632. self._subscription = value
  2633. @property
  2634. def publication(self):
  2635. if self._publication is None and self._from_fbs:
  2636. self._publication = self._from_fbs.Publication()
  2637. return self._publication
  2638. @publication.setter
  2639. def publication(self, value):
  2640. assert(value is None or type(value) in six.integer_types)
  2641. self._publication = value
  2642. @property
  2643. def args(self):
  2644. if self._args is None and self._from_fbs:
  2645. if self._from_fbs.ArgsLength():
  2646. self._args = cbor.loads(bytes(self._from_fbs.ArgsAsBytes()))
  2647. return self._args
  2648. @args.setter
  2649. def args(self, value):
  2650. assert(value is None or type(value) in [list, tuple])
  2651. self._args = value
  2652. @property
  2653. def kwargs(self):
  2654. if self._kwargs is None and self._from_fbs:
  2655. if self._from_fbs.KwargsLength():
  2656. self._kwargs = cbor.loads(bytes(self._from_fbs.KwargsAsBytes()))
  2657. return self._kwargs
  2658. @kwargs.setter
  2659. def kwargs(self, value):
  2660. assert(value is None or type(value) == dict)
  2661. self._kwargs = value
  2662. @property
  2663. def payload(self):
  2664. if self._payload is None and self._from_fbs:
  2665. if self._from_fbs.PayloadLength():
  2666. self._payload = self._from_fbs.PayloadAsBytes()
  2667. return self._payload
  2668. @payload.setter
  2669. def payload(self, value):
  2670. assert value is None or type(value) == bytes
  2671. self._payload = value
  2672. @property
  2673. def publisher(self):
  2674. if self._publisher is None and self._from_fbs:
  2675. publisher = self._from_fbs.Publisher()
  2676. if publisher:
  2677. self._publisher = publisher
  2678. return self._publisher
  2679. @publisher.setter
  2680. def publisher(self, value):
  2681. assert value is None or type(value) == int
  2682. self._publisher = value
  2683. @property
  2684. def publisher_authid(self):
  2685. if self._publisher_authid is None and self._from_fbs:
  2686. s = self._from_fbs.PublisherAuthid()
  2687. if s:
  2688. self._publisher_authid = s.decode('utf8')
  2689. return self._publisher_authid
  2690. @publisher_authid.setter
  2691. def publisher_authid(self, value):
  2692. assert value is None or type(value) == str
  2693. self._publisher_authid = value
  2694. @property
  2695. def publisher_authrole(self):
  2696. if self._publisher_authrole is None and self._from_fbs:
  2697. s = self._from_fbs.PublisherAuthrole()
  2698. if s:
  2699. self._publisher_authrole = s.decode('utf8')
  2700. return self._publisher_authrole
  2701. @publisher_authrole.setter
  2702. def publisher_authrole(self, value):
  2703. assert value is None or type(value) == str
  2704. self._publisher_authrole = value
  2705. @property
  2706. def topic(self):
  2707. if self._topic is None and self._from_fbs:
  2708. s = self._from_fbs.Topic()
  2709. if s:
  2710. self._topic = s.decode('utf8')
  2711. return self._topic
  2712. @topic.setter
  2713. def topic(self, value):
  2714. assert value is None or type(value) == str
  2715. self._topic = value
  2716. @property
  2717. def retained(self):
  2718. if self._retained is None and self._from_fbs:
  2719. self._retained = self._from_fbs.Retained()
  2720. return self._retained
  2721. @retained.setter
  2722. def retained(self, value):
  2723. assert value is None or type(value) == bool
  2724. self._retained = value
  2725. @property
  2726. def x_acknowledged_delivery(self):
  2727. if self._x_acknowledged_delivery is None and self._from_fbs:
  2728. x_acknowledged_delivery = self._from_fbs.Acknowledge()
  2729. if x_acknowledged_delivery:
  2730. self._x_acknowledged_delivery = x_acknowledged_delivery
  2731. return self._x_acknowledged_delivery
  2732. @x_acknowledged_delivery.setter
  2733. def x_acknowledged_delivery(self, value):
  2734. assert value is None or type(value) == bool
  2735. self._x_acknowledged_delivery = value
  2736. @property
  2737. def enc_algo(self):
  2738. if self._enc_algo is None and self._from_fbs:
  2739. enc_algo = self._from_fbs.EncAlgo()
  2740. if enc_algo:
  2741. self._enc_algo = enc_algo
  2742. return self._enc_algo
  2743. @enc_algo.setter
  2744. def enc_algo(self, value):
  2745. assert value is None or value in [ENC_ALGO_CRYPTOBOX, ENC_ALGO_MQTT, ENC_ALGO_XBR]
  2746. self._enc_algo = value
  2747. @property
  2748. def enc_key(self):
  2749. if self._enc_key is None and self._from_fbs:
  2750. if self._from_fbs.EncKeyLength():
  2751. self._enc_key = self._from_fbs.EncKeyAsBytes()
  2752. return self._enc_key
  2753. @enc_key.setter
  2754. def enc_key(self, value):
  2755. assert value is None or type(value) == bytes
  2756. self._enc_key = value
  2757. @property
  2758. def enc_serializer(self):
  2759. if self._enc_serializer is None and self._from_fbs:
  2760. enc_serializer = self._from_fbs.EncSerializer()
  2761. if enc_serializer:
  2762. self._enc_serializer = enc_serializer
  2763. return self._enc_serializer
  2764. @enc_serializer.setter
  2765. def enc_serializer(self, value):
  2766. assert value is None or value in [ENC_SER_JSON, ENC_SER_MSGPACK, ENC_SER_CBOR, ENC_SER_UBJSON]
  2767. self._enc_serializer = value
  2768. @property
  2769. def forward_for(self):
  2770. # FIXME
  2771. return self._forward_for
  2772. @forward_for.setter
  2773. def forward_for(self, value):
  2774. # FIXME
  2775. self._forward_for = value
  2776. @staticmethod
  2777. def cast(buf):
  2778. return Event(from_fbs=message_fbs.Event.GetRootAsEvent(buf, 0))
  2779. def build(self, builder):
  2780. args = self.args
  2781. if args:
  2782. args = builder.CreateByteVector(cbor.dumps(args))
  2783. kwargs = self.kwargs
  2784. if kwargs:
  2785. kwargs = builder.CreateByteVector(cbor.dumps(kwargs))
  2786. payload = self.payload
  2787. if payload:
  2788. payload = builder.CreateByteVector(payload)
  2789. publisher_authid = self.publisher_authid
  2790. if publisher_authid:
  2791. publisher_authid = builder.CreateString(publisher_authid)
  2792. publisher_authrole = self.publisher_authrole
  2793. if publisher_authrole:
  2794. publisher_authrole = builder.CreateString(publisher_authrole)
  2795. topic = self.topic
  2796. if topic:
  2797. topic = builder.CreateString(topic)
  2798. enc_key = self.enc_key
  2799. if enc_key:
  2800. enc_key = builder.CreateByteVector(enc_key)
  2801. message_fbs.EventGen.EventStart(builder)
  2802. if self.subscription:
  2803. message_fbs.EventGen.EventAddSubscription(builder, self.subscription)
  2804. if self.publication:
  2805. message_fbs.EventGen.EventAddPublication(builder, self.publication)
  2806. if args:
  2807. message_fbs.EventGen.EventAddArgs(builder, args)
  2808. if kwargs:
  2809. message_fbs.EventGen.EventAddKwargs(builder, kwargs)
  2810. if payload:
  2811. message_fbs.EventGen.EventAddPayload(builder, payload)
  2812. if self.publisher:
  2813. message_fbs.EventGen.EventAddPublisher(builder, self.publisher)
  2814. if publisher_authid:
  2815. message_fbs.EventGen.EventAddPublisherAuthid(builder, publisher_authid)
  2816. if publisher_authrole:
  2817. message_fbs.EventGen.EventAddPublisherAuthrole(builder, publisher_authrole)
  2818. if topic:
  2819. message_fbs.EventGen.EventAddTopic(builder, topic)
  2820. if self.retained is not None:
  2821. message_fbs.EventGen.EventAddRetained(builder, self.retained)
  2822. if self.x_acknowledged_delivery is not None:
  2823. message_fbs.EventGen.EventAddAcknowledge(builder, self.x_acknowledged_delivery)
  2824. if self.enc_algo:
  2825. message_fbs.EventGen.EventAddEncAlgo(builder, self.enc_algo)
  2826. if enc_key:
  2827. message_fbs.EventGen.EventAddEncKey(builder, enc_key)
  2828. if self.enc_serializer:
  2829. message_fbs.EventGen.EventAddEncSerializer(builder, self.enc_serializer)
  2830. # FIXME: add forward_for
  2831. msg = message_fbs.EventGen.EventEnd(builder)
  2832. message_fbs.Message.MessageStart(builder)
  2833. message_fbs.Message.MessageAddMsgType(builder, message_fbs.MessageType.EVENT)
  2834. message_fbs.Message.MessageAddMsg(builder, msg)
  2835. union_msg = message_fbs.Message.MessageEnd(builder)
  2836. return union_msg
  2837. @staticmethod
  2838. def parse(wmsg):
  2839. """
  2840. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  2841. :param wmsg: The unserialized raw message.
  2842. :type wmsg: list
  2843. :returns: An instance of this class.
  2844. """
  2845. # this should already be verified by WampSerializer.unserialize
  2846. assert(len(wmsg) > 0 and wmsg[0] == Event.MESSAGE_TYPE)
  2847. if len(wmsg) not in (4, 5, 6):
  2848. raise ProtocolError("invalid message length {0} for EVENT".format(len(wmsg)))
  2849. subscription = check_or_raise_id(wmsg[1], u"'subscription' in EVENT")
  2850. publication = check_or_raise_id(wmsg[2], u"'publication' in EVENT")
  2851. details = check_or_raise_extra(wmsg[3], u"'details' in EVENT")
  2852. args = None
  2853. kwargs = None
  2854. payload = None
  2855. enc_algo = None
  2856. enc_key = None
  2857. enc_serializer = None
  2858. if len(wmsg) == 5 and type(wmsg[4]) == six.binary_type:
  2859. payload = wmsg[4]
  2860. enc_algo = details.get(u'enc_algo', None)
  2861. if enc_algo and not is_valid_enc_algo(enc_algo):
  2862. raise ProtocolError("invalid value {0} for 'enc_algo' detail in EVENT".format(enc_algo))
  2863. enc_key = details.get(u'enc_key', None)
  2864. if enc_key and type(enc_key) != six.text_type:
  2865. raise ProtocolError("invalid type {0} for 'enc_key' detail in EVENT".format(type(enc_key)))
  2866. enc_serializer = details.get(u'enc_serializer', None)
  2867. if enc_serializer and not is_valid_enc_serializer(enc_serializer):
  2868. raise ProtocolError("invalid value {0} for 'enc_serializer' detail in EVENT".format(enc_serializer))
  2869. else:
  2870. if len(wmsg) > 4:
  2871. args = wmsg[4]
  2872. if args is not None and type(args) != list:
  2873. raise ProtocolError("invalid type {0} for 'args' in EVENT".format(type(args)))
  2874. if len(wmsg) > 5:
  2875. kwargs = wmsg[5]
  2876. if type(kwargs) != dict:
  2877. raise ProtocolError("invalid type {0} for 'kwargs' in EVENT".format(type(kwargs)))
  2878. publisher = None
  2879. publisher_authid = None
  2880. publisher_authrole = None
  2881. topic = None
  2882. retained = None
  2883. forward_for = None
  2884. x_acknowledged_delivery = None
  2885. if u'publisher' in details:
  2886. detail_publisher = details[u'publisher']
  2887. if type(detail_publisher) not in six.integer_types:
  2888. raise ProtocolError("invalid type {0} for 'publisher' detail in EVENT".format(type(detail_publisher)))
  2889. publisher = detail_publisher
  2890. if u'publisher_authid' in details:
  2891. detail_publisher_authid = details[u'publisher_authid']
  2892. if type(detail_publisher_authid) != six.text_type:
  2893. raise ProtocolError("invalid type {0} for 'publisher_authid' detail in EVENT".format(type(detail_publisher_authid)))
  2894. publisher_authid = detail_publisher_authid
  2895. if u'publisher_authrole' in details:
  2896. detail_publisher_authrole = details[u'publisher_authrole']
  2897. if type(detail_publisher_authrole) != six.text_type:
  2898. raise ProtocolError("invalid type {0} for 'publisher_authrole' detail in EVENT".format(type(detail_publisher_authrole)))
  2899. publisher_authrole = detail_publisher_authrole
  2900. if u'topic' in details:
  2901. detail_topic = details[u'topic']
  2902. if type(detail_topic) != six.text_type:
  2903. raise ProtocolError("invalid type {0} for 'topic' detail in EVENT".format(type(detail_topic)))
  2904. topic = detail_topic
  2905. if u'retained' in details:
  2906. retained = details[u'retained']
  2907. if type(retained) != bool:
  2908. raise ProtocolError("invalid type {0} for 'retained' detail in EVENT".format(type(retained)))
  2909. if u'x_acknowledged_delivery' in details:
  2910. x_acknowledged_delivery = details[u'x_acknowledged_delivery']
  2911. if type(x_acknowledged_delivery) != bool:
  2912. raise ProtocolError("invalid type {0} for 'x_acknowledged_delivery' detail in EVENT".format(type(x_acknowledged_delivery)))
  2913. if u'forward_for' in details:
  2914. forward_for = details[u'forward_for']
  2915. valid = False
  2916. if type(forward_for) == list:
  2917. for ff in forward_for:
  2918. if type(ff) != dict:
  2919. break
  2920. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  2921. break
  2922. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  2923. break
  2924. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  2925. break
  2926. valid = True
  2927. if not valid:
  2928. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in EVENT")
  2929. obj = Event(subscription,
  2930. publication,
  2931. args=args,
  2932. kwargs=kwargs,
  2933. payload=payload,
  2934. publisher=publisher,
  2935. publisher_authid=publisher_authid,
  2936. publisher_authrole=publisher_authrole,
  2937. topic=topic,
  2938. retained=retained,
  2939. x_acknowledged_delivery=x_acknowledged_delivery,
  2940. enc_algo=enc_algo,
  2941. enc_key=enc_key,
  2942. enc_serializer=enc_serializer,
  2943. forward_for=forward_for)
  2944. return obj
  2945. def marshal(self):
  2946. """
  2947. Marshal this object into a raw message for subsequent serialization to bytes.
  2948. :returns: The serialized raw message.
  2949. :rtype: list
  2950. """
  2951. details = {}
  2952. if self.publisher is not None:
  2953. details[u'publisher'] = self.publisher
  2954. if self.publisher_authid is not None:
  2955. details[u'publisher_authid'] = self.publisher_authid
  2956. if self.publisher_authrole is not None:
  2957. details[u'publisher_authrole'] = self.publisher_authrole
  2958. if self.topic is not None:
  2959. details[u'topic'] = self.topic
  2960. if self.retained is not None:
  2961. details[u'retained'] = self.retained
  2962. if self.x_acknowledged_delivery is not None:
  2963. details[u'x_acknowledged_delivery'] = self.x_acknowledged_delivery
  2964. if self.forward_for is not None:
  2965. details[u'forward_for'] = self.forward_for
  2966. if self.payload:
  2967. if self.enc_algo is not None:
  2968. details[u'enc_algo'] = self.enc_algo
  2969. if self.enc_key is not None:
  2970. details[u'enc_key'] = self.enc_key
  2971. if self.enc_serializer is not None:
  2972. details[u'enc_serializer'] = self.enc_serializer
  2973. return [Event.MESSAGE_TYPE, self.subscription, self.publication, details, self.payload]
  2974. else:
  2975. if self.kwargs:
  2976. return [Event.MESSAGE_TYPE, self.subscription, self.publication, details, self.args, self.kwargs]
  2977. elif self.args:
  2978. return [Event.MESSAGE_TYPE, self.subscription, self.publication, details, self.args]
  2979. else:
  2980. return [Event.MESSAGE_TYPE, self.subscription, self.publication, details]
  2981. def __str__(self):
  2982. """
  2983. Returns string representation of this message.
  2984. """
  2985. return u"Event(subscription={}, publication={}, args={}, kwargs={}, publisher={}, publisher_authid={}, publisher_authrole={}, topic={}, retained={}, enc_algo={}, enc_key={}, enc_serializer={}, payload={}, forward_for={})".format(self.subscription, self.publication, self.args, self.kwargs, self.publisher, self.publisher_authid, self.publisher_authrole, self.topic, self.retained, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), self.forward_for)
  2986. class EventReceived(Message):
  2987. """
  2988. A WAMP ``EVENT_RECEIVED`` message.
  2989. Format: ``[EVENT_RECEIVED, EVENT.Publication|id]``
  2990. """
  2991. # NOTE: Implementation-specific message! Should be 37 on ratification.
  2992. MESSAGE_TYPE = 337
  2993. """
  2994. The WAMP message code for this type of message.
  2995. """
  2996. __slots__ = (
  2997. 'publication',
  2998. )
  2999. def __init__(self, publication):
  3000. """
  3001. :param publication: The publication ID for the sent event.
  3002. :type publication: int
  3003. """
  3004. assert(type(publication) in six.integer_types)
  3005. Message.__init__(self)
  3006. self.publication = publication
  3007. @staticmethod
  3008. def parse(wmsg):
  3009. """
  3010. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3011. :param wmsg: The unserialized raw message.
  3012. :type wmsg: list
  3013. :returns: An instance of this class.
  3014. """
  3015. # this should already be verified by WampSerializer.unserialize
  3016. assert(len(wmsg) > 0 and wmsg[0] == EventReceived.MESSAGE_TYPE)
  3017. if len(wmsg) != 2:
  3018. raise ProtocolError("invalid message length {0} for EVENT_RECEIVED".format(len(wmsg)))
  3019. publication = check_or_raise_id(wmsg[1], u"'publication' in EVENT_RECEIVED")
  3020. obj = EventReceived(publication)
  3021. return obj
  3022. def marshal(self):
  3023. """
  3024. Marshal this object into a raw message for subsequent serialization to bytes.
  3025. :returns: The serialized raw message.
  3026. :rtype: list
  3027. """
  3028. return [EventReceived.MESSAGE_TYPE, self.publication]
  3029. def __str__(self):
  3030. """
  3031. Returns string representation of this message.
  3032. """
  3033. return u"EventReceived(publication={})".format(self.publication)
  3034. class Call(Message):
  3035. """
  3036. A WAMP ``CALL`` message.
  3037. Formats:
  3038. * ``[CALL, Request|id, Options|dict, Procedure|uri]``
  3039. * ``[CALL, Request|id, Options|dict, Procedure|uri, Arguments|list]``
  3040. * ``[CALL, Request|id, Options|dict, Procedure|uri, Arguments|list, ArgumentsKw|dict]``
  3041. * ``[CALL, Request|id, Options|dict, Procedure|uri, Payload|binary]``
  3042. """
  3043. MESSAGE_TYPE = 48
  3044. """
  3045. The WAMP message code for this type of message.
  3046. """
  3047. __slots__ = (
  3048. 'request',
  3049. 'procedure',
  3050. 'args',
  3051. 'kwargs',
  3052. 'payload',
  3053. 'timeout',
  3054. 'receive_progress',
  3055. 'enc_algo',
  3056. 'enc_key',
  3057. 'enc_serializer',
  3058. 'caller',
  3059. 'caller_authid',
  3060. 'caller_authrole',
  3061. 'forward_for',
  3062. )
  3063. def __init__(self,
  3064. request,
  3065. procedure,
  3066. args=None,
  3067. kwargs=None,
  3068. payload=None,
  3069. timeout=None,
  3070. receive_progress=None,
  3071. enc_algo=None,
  3072. enc_key=None,
  3073. enc_serializer=None,
  3074. caller=None,
  3075. caller_authid=None,
  3076. caller_authrole=None,
  3077. forward_for=None):
  3078. """
  3079. :param request: The WAMP request ID of this request.
  3080. :type request: int
  3081. :param procedure: The WAMP or application URI of the procedure which should be called.
  3082. :type procedure: str
  3083. :param args: Positional values for application-defined call arguments.
  3084. Must be serializable using any serializers in use.
  3085. :type args: list or tuple or None
  3086. :param kwargs: Keyword values for application-defined call arguments.
  3087. Must be serializable using any serializers in use.
  3088. :type kwargs: dict or None
  3089. :param payload: Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
  3090. :type payload: bytes or None
  3091. :param timeout: If present, let the callee automatically cancel
  3092. the call after this ms.
  3093. :type timeout: int or None
  3094. :param receive_progress: If ``True``, indicates that the caller wants to receive
  3095. progressive call results.
  3096. :type receive_progress: bool or None
  3097. :param enc_algo: If using payload transparency, the encoding algorithm that was used to encode the payload.
  3098. :type enc_algo: str or None
  3099. :param enc_key: If using payload transparency with an encryption algorithm, the payload encryption key.
  3100. :type enc_key: str or None
  3101. :param enc_serializer: If using payload transparency, the payload object serializer that was used encoding the payload.
  3102. :type enc_serializer: str or None
  3103. :param caller: The WAMP session ID of the caller. Only filled if caller is disclosed.
  3104. :type caller: None or int
  3105. :param caller_authid: The WAMP authid of the caller. Only filled if caller is disclosed.
  3106. :type caller_authid: None or unicode
  3107. :param caller_authrole: The WAMP authrole of the caller. Only filled if caller is disclosed.
  3108. :type caller_authrole: None or unicode
  3109. :param forward_for: When this Publish is forwarded for a client (or from an intermediary router).
  3110. :type forward_for: list[dict]
  3111. """
  3112. assert(type(request) in six.integer_types)
  3113. assert(type(procedure) == six.text_type)
  3114. assert(args is None or type(args) in [list, tuple])
  3115. assert(kwargs is None or type(kwargs) == dict)
  3116. assert(payload is None or type(payload) == six.binary_type)
  3117. assert(payload is None or (payload is not None and args is None and kwargs is None))
  3118. assert(timeout is None or type(timeout) in six.integer_types)
  3119. assert(receive_progress is None or type(receive_progress) == bool)
  3120. # payload transparency related knobs
  3121. assert(enc_algo is None or is_valid_enc_algo(enc_algo))
  3122. assert(enc_key is None or type(enc_key) == six.text_type)
  3123. assert(enc_serializer is None or is_valid_enc_serializer(enc_serializer))
  3124. assert((enc_algo is None and enc_key is None and enc_serializer is None) or (payload is not None and enc_algo is not None))
  3125. assert(caller is None or type(caller) in six.integer_types)
  3126. assert(caller_authid is None or type(caller_authid) == six.text_type)
  3127. assert(caller_authrole is None or type(caller_authrole) == six.text_type)
  3128. assert(forward_for is None or type(forward_for) == list)
  3129. if forward_for:
  3130. for ff in forward_for:
  3131. assert type(ff) == dict
  3132. assert 'session' in ff and type(ff['session']) in six.integer_types
  3133. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  3134. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  3135. Message.__init__(self)
  3136. self.request = request
  3137. self.procedure = procedure
  3138. self.args = args
  3139. self.kwargs = _validate_kwargs(kwargs)
  3140. self.payload = payload
  3141. self.timeout = timeout
  3142. self.receive_progress = receive_progress
  3143. # payload transparency related knobs
  3144. self.enc_algo = enc_algo
  3145. self.enc_key = enc_key
  3146. self.enc_serializer = enc_serializer
  3147. # message forwarding
  3148. self.caller = caller
  3149. self.caller_authid = caller_authid
  3150. self.caller_authrole = caller_authrole
  3151. self.forward_for = forward_for
  3152. @staticmethod
  3153. def parse(wmsg):
  3154. """
  3155. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3156. :param wmsg: The unserialized raw message.
  3157. :type wmsg: list
  3158. :returns: An instance of this class.
  3159. """
  3160. # this should already be verified by WampSerializer.unserialize
  3161. assert(len(wmsg) > 0 and wmsg[0] == Call.MESSAGE_TYPE)
  3162. if len(wmsg) not in (4, 5, 6):
  3163. raise ProtocolError("invalid message length {0} for CALL".format(len(wmsg)))
  3164. request = check_or_raise_id(wmsg[1], u"'request' in CALL")
  3165. options = check_or_raise_extra(wmsg[2], u"'options' in CALL")
  3166. procedure = check_or_raise_uri(wmsg[3], u"'procedure' in CALL")
  3167. args = None
  3168. kwargs = None
  3169. payload = None
  3170. enc_algo = None
  3171. enc_key = None
  3172. enc_serializer = None
  3173. if len(wmsg) == 5 and type(wmsg[4]) in [six.text_type, six.binary_type]:
  3174. payload = wmsg[4]
  3175. enc_algo = options.get(u'enc_algo', None)
  3176. if enc_algo and not is_valid_enc_algo(enc_algo):
  3177. raise ProtocolError("invalid value {0} for 'enc_algo' detail in CALL".format(enc_algo))
  3178. enc_key = options.get(u'enc_key', None)
  3179. if enc_key and type(enc_key) != six.text_type:
  3180. raise ProtocolError("invalid type {0} for 'enc_key' detail in CALL".format(type(enc_key)))
  3181. enc_serializer = options.get(u'enc_serializer', None)
  3182. if enc_serializer and not is_valid_enc_serializer(enc_serializer):
  3183. raise ProtocolError("invalid value {0} for 'enc_serializer' detail in CALL".format(enc_serializer))
  3184. else:
  3185. if len(wmsg) > 4:
  3186. args = wmsg[4]
  3187. if args is not None and type(args) != list:
  3188. raise ProtocolError("invalid type {0} for 'args' in CALL".format(type(args)))
  3189. if len(wmsg) > 5:
  3190. kwargs = wmsg[5]
  3191. if type(kwargs) != dict:
  3192. raise ProtocolError("invalid type {0} for 'kwargs' in CALL".format(type(kwargs)))
  3193. timeout = None
  3194. receive_progress = None
  3195. caller = None
  3196. caller_authid = None
  3197. caller_authrole = None
  3198. forward_for = None
  3199. if u'timeout' in options:
  3200. option_timeout = options[u'timeout']
  3201. if type(option_timeout) not in six.integer_types:
  3202. raise ProtocolError("invalid type {0} for 'timeout' option in CALL".format(type(option_timeout)))
  3203. if option_timeout < 0:
  3204. raise ProtocolError("invalid value {0} for 'timeout' option in CALL".format(option_timeout))
  3205. timeout = option_timeout
  3206. if u'receive_progress' in options:
  3207. option_receive_progress = options[u'receive_progress']
  3208. if type(option_receive_progress) != bool:
  3209. raise ProtocolError("invalid type {0} for 'receive_progress' option in CALL".format(type(option_receive_progress)))
  3210. receive_progress = option_receive_progress
  3211. if u'caller' in options:
  3212. option_caller = options[u'caller']
  3213. if type(option_caller) not in six.integer_types:
  3214. raise ProtocolError("invalid type {0} for 'caller' detail in CALL".format(type(option_caller)))
  3215. caller = option_caller
  3216. if u'caller_authid' in options:
  3217. option_caller_authid = options[u'caller_authid']
  3218. if type(option_caller_authid) != six.text_type:
  3219. raise ProtocolError("invalid type {0} for 'caller_authid' detail in CALL".format(type(option_caller_authid)))
  3220. caller_authid = option_caller_authid
  3221. if u'caller_authrole' in options:
  3222. option_caller_authrole = options[u'caller_authrole']
  3223. if type(option_caller_authrole) != six.text_type:
  3224. raise ProtocolError("invalid type {0} for 'caller_authrole' detail in CALL".format(type(option_caller_authrole)))
  3225. caller_authrole = option_caller_authrole
  3226. if u'forward_for' in options:
  3227. forward_for = options[u'forward_for']
  3228. valid = False
  3229. if type(forward_for) == list:
  3230. for ff in forward_for:
  3231. if type(ff) != dict:
  3232. break
  3233. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  3234. break
  3235. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  3236. break
  3237. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  3238. break
  3239. valid = True
  3240. if not valid:
  3241. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in CALL")
  3242. obj = Call(request,
  3243. procedure,
  3244. args=args,
  3245. kwargs=kwargs,
  3246. payload=payload,
  3247. timeout=timeout,
  3248. receive_progress=receive_progress,
  3249. enc_algo=enc_algo,
  3250. enc_key=enc_key,
  3251. enc_serializer=enc_serializer,
  3252. caller=caller,
  3253. caller_authid=caller_authid,
  3254. caller_authrole=caller_authrole,
  3255. forward_for=forward_for)
  3256. return obj
  3257. def marshal_options(self):
  3258. options = {}
  3259. if self.timeout is not None:
  3260. options[u'timeout'] = self.timeout
  3261. if self.receive_progress is not None:
  3262. options[u'receive_progress'] = self.receive_progress
  3263. if self.payload:
  3264. if self.enc_algo is not None:
  3265. options[u'enc_algo'] = self.enc_algo
  3266. if self.enc_key is not None:
  3267. options[u'enc_key'] = self.enc_key
  3268. if self.enc_serializer is not None:
  3269. options[u'enc_serializer'] = self.enc_serializer
  3270. if self.caller is not None:
  3271. options[u'caller'] = self.caller
  3272. if self.caller_authid is not None:
  3273. options[u'caller_authid'] = self.caller_authid
  3274. if self.caller_authrole is not None:
  3275. options[u'caller_authrole'] = self.caller_authrole
  3276. if self.forward_for is not None:
  3277. options[u'forward_for'] = self.forward_for
  3278. return options
  3279. def marshal(self):
  3280. """
  3281. Marshal this object into a raw message for subsequent serialization to bytes.
  3282. :returns: The serialized raw message.
  3283. :rtype: list
  3284. """
  3285. options = self.marshal_options()
  3286. if self.payload:
  3287. return [Call.MESSAGE_TYPE, self.request, options, self.procedure, self.payload]
  3288. else:
  3289. if self.kwargs:
  3290. return [Call.MESSAGE_TYPE, self.request, options, self.procedure, self.args, self.kwargs]
  3291. elif self.args:
  3292. return [Call.MESSAGE_TYPE, self.request, options, self.procedure, self.args]
  3293. else:
  3294. return [Call.MESSAGE_TYPE, self.request, options, self.procedure]
  3295. def __str__(self):
  3296. """
  3297. Returns string representation of this message.
  3298. """
  3299. return u"Call(request={}, procedure={}, args={}, kwargs={}, timeout={}, receive_progress={}, enc_algo={}, enc_key={}, enc_serializer={}, payload={}, caller={}, caller_authid={}, caller_authrole={}, forward_for={})".format(self.request, self.procedure, self.args, self.kwargs, self.timeout, self.receive_progress, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), self.caller, self.caller_authid, self.caller_authrole, self.forward_for)
  3300. class Cancel(Message):
  3301. """
  3302. A WAMP ``CANCEL`` message.
  3303. Format: ``[CANCEL, CALL.Request|id, Options|dict]``
  3304. See: https://wamp-proto.org/static/rfc/draft-oberstet-hybi-crossbar-wamp.html#rfc.section.14.3.4
  3305. """
  3306. MESSAGE_TYPE = 49
  3307. """
  3308. The WAMP message code for this type of message.
  3309. """
  3310. SKIP = u'skip'
  3311. KILL = u'kill'
  3312. KILLNOWAIT = u'killnowait'
  3313. __slots__ = (
  3314. 'request',
  3315. 'mode',
  3316. 'forward_for',
  3317. )
  3318. def __init__(self, request, mode=None, forward_for=None):
  3319. """
  3320. :param request: The WAMP request ID of the original `CALL` to cancel.
  3321. :type request: int
  3322. :param mode: Specifies how to cancel the call (``"skip"``, ``"killnowait"`` or ``"kill"``).
  3323. :type mode: str or None
  3324. :param forward_for: When this Cancel is forwarded for a client (or from an intermediary router).
  3325. :type forward_for: list[dict]
  3326. """
  3327. assert(type(request) in six.integer_types)
  3328. assert(mode is None or type(mode) == six.text_type)
  3329. assert(mode in [None, self.SKIP, self.KILLNOWAIT, self.KILL])
  3330. assert(forward_for is None or type(forward_for) == list)
  3331. if forward_for:
  3332. for ff in forward_for:
  3333. assert type(ff) == dict
  3334. assert 'session' in ff and type(ff['session']) in six.integer_types
  3335. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  3336. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  3337. Message.__init__(self)
  3338. self.request = request
  3339. self.mode = mode
  3340. # message forwarding
  3341. self.forward_for = forward_for
  3342. @staticmethod
  3343. def parse(wmsg):
  3344. """
  3345. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3346. :param wmsg: The unserialized raw message.
  3347. :type wmsg: list
  3348. :returns: An instance of this class.
  3349. """
  3350. # this should already be verified by WampSerializer.unserialize
  3351. assert(len(wmsg) > 0 and wmsg[0] == Cancel.MESSAGE_TYPE)
  3352. if len(wmsg) != 3:
  3353. raise ProtocolError("invalid message length {0} for CANCEL".format(len(wmsg)))
  3354. request = check_or_raise_id(wmsg[1], u"'request' in CANCEL")
  3355. options = check_or_raise_extra(wmsg[2], u"'options' in CANCEL")
  3356. # options
  3357. #
  3358. mode = None
  3359. forward_for = None
  3360. if u'mode' in options:
  3361. option_mode = options[u'mode']
  3362. if type(option_mode) != six.text_type:
  3363. raise ProtocolError("invalid type {0} for 'mode' option in CANCEL".format(type(option_mode)))
  3364. if option_mode not in [Cancel.SKIP, Cancel.KILLNOWAIT, Cancel.KILL]:
  3365. raise ProtocolError("invalid value '{0}' for 'mode' option in CANCEL".format(option_mode))
  3366. mode = option_mode
  3367. if u'forward_for' in options:
  3368. forward_for = options[u'forward_for']
  3369. valid = False
  3370. if type(forward_for) == list:
  3371. for ff in forward_for:
  3372. if type(ff) != dict:
  3373. break
  3374. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  3375. break
  3376. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  3377. break
  3378. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  3379. break
  3380. valid = True
  3381. if not valid:
  3382. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in CANCEL")
  3383. obj = Cancel(request, mode=mode, forward_for=forward_for)
  3384. return obj
  3385. def marshal(self):
  3386. """
  3387. Marshal this object into a raw message for subsequent serialization to bytes.
  3388. :returns: The serialized raw message.
  3389. :rtype: list
  3390. """
  3391. options = {}
  3392. if self.mode is not None:
  3393. options[u'mode'] = self.mode
  3394. if self.forward_for is not None:
  3395. options[u'forward_for'] = self.forward_for
  3396. return [Cancel.MESSAGE_TYPE, self.request, options]
  3397. def __str__(self):
  3398. """
  3399. Returns string representation of this message.
  3400. """
  3401. return u"Cancel(request={0}, mode={1})".format(self.request, self.mode)
  3402. class Result(Message):
  3403. """
  3404. A WAMP ``RESULT`` message.
  3405. Formats:
  3406. * ``[RESULT, CALL.Request|id, Details|dict]``
  3407. * ``[RESULT, CALL.Request|id, Details|dict, YIELD.Arguments|list]``
  3408. * ``[RESULT, CALL.Request|id, Details|dict, YIELD.Arguments|list, YIELD.ArgumentsKw|dict]``
  3409. * ``[RESULT, CALL.Request|id, Details|dict, Payload|binary]``
  3410. """
  3411. MESSAGE_TYPE = 50
  3412. """
  3413. The WAMP message code for this type of message.
  3414. """
  3415. __slots__ = (
  3416. 'request',
  3417. 'args',
  3418. 'kwargs',
  3419. 'payload',
  3420. 'progress',
  3421. 'enc_algo',
  3422. 'enc_key',
  3423. 'enc_serializer',
  3424. 'callee',
  3425. 'callee_authid',
  3426. 'callee_authrole',
  3427. 'forward_for',
  3428. )
  3429. def __init__(self,
  3430. request,
  3431. args=None,
  3432. kwargs=None,
  3433. payload=None,
  3434. progress=None,
  3435. enc_algo=None,
  3436. enc_key=None,
  3437. enc_serializer=None,
  3438. callee=None,
  3439. callee_authid=None,
  3440. callee_authrole=None,
  3441. forward_for=None):
  3442. """
  3443. :param request: The request ID of the original `CALL` request.
  3444. :type request: int
  3445. :param args: Positional values for application-defined event payload.
  3446. Must be serializable using any serializers in use.
  3447. :type args: list or tuple or None
  3448. :param kwargs: Keyword values for application-defined event payload.
  3449. Must be serializable using any serializers in use.
  3450. :type kwargs: dict or None
  3451. :param payload: Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
  3452. :type payload: bytes or None
  3453. :param progress: If ``True``, this result is a progressive call result, and subsequent
  3454. results (or a final error) will follow.
  3455. :type progress: bool or None
  3456. :param enc_algo: If using payload transparency, the encoding algorithm that was used to encode the payload.
  3457. :type enc_algo: str or None
  3458. :param enc_key: If using payload transparency with an encryption algorithm, the payload encryption key.
  3459. :type enc_key: str or None
  3460. :param enc_serializer: If using payload transparency, the payload object serializer that was used encoding the payload.
  3461. :type enc_serializer: str or None
  3462. :param callee: The WAMP session ID of the effective callee that responded with the result. Only filled if callee is disclosed.
  3463. :type callee: None or int
  3464. :param callee_authid: The WAMP authid of the responding callee. Only filled if callee is disclosed.
  3465. :type callee_authid: None or unicode
  3466. :param callee_authrole: The WAMP authrole of the responding callee. Only filled if callee is disclosed.
  3467. :type callee_authrole: None or unicode
  3468. :param forward_for: When this Result is forwarded for a client/callee (or from an intermediary router).
  3469. :type forward_for: list[dict]
  3470. """
  3471. assert(type(request) in six.integer_types)
  3472. assert(args is None or type(args) in [list, tuple])
  3473. assert(kwargs is None or type(kwargs) == dict)
  3474. assert(payload is None or type(payload) == six.binary_type)
  3475. assert(payload is None or (payload is not None and args is None and kwargs is None))
  3476. assert(progress is None or type(progress) == bool)
  3477. assert(enc_algo is None or is_valid_enc_algo(enc_algo))
  3478. assert(enc_key is None or type(enc_key) == six.text_type)
  3479. assert(enc_serializer is None or is_valid_enc_serializer(enc_serializer))
  3480. assert((enc_algo is None and enc_key is None and enc_serializer is None) or (payload is not None and enc_algo is not None))
  3481. assert(callee is None or type(callee) in six.integer_types)
  3482. assert(callee_authid is None or type(callee_authid) == six.text_type)
  3483. assert(callee_authrole is None or type(callee_authrole) == six.text_type)
  3484. assert(forward_for is None or type(forward_for) == list)
  3485. if forward_for:
  3486. for ff in forward_for:
  3487. assert type(ff) == dict
  3488. assert 'session' in ff and type(ff['session']) in six.integer_types
  3489. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  3490. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  3491. Message.__init__(self)
  3492. self.request = request
  3493. self.args = args
  3494. self.kwargs = _validate_kwargs(kwargs)
  3495. self.payload = payload
  3496. self.progress = progress
  3497. # payload transparency related knobs
  3498. self.enc_algo = enc_algo
  3499. self.enc_key = enc_key
  3500. self.enc_serializer = enc_serializer
  3501. # effective callee that responded with the result
  3502. self.callee = callee
  3503. self.callee_authid = callee_authid
  3504. self.callee_authrole = callee_authrole
  3505. # message forwarding
  3506. self.forward_for = forward_for
  3507. @staticmethod
  3508. def parse(wmsg):
  3509. """
  3510. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3511. :param wmsg: The unserialized raw message.
  3512. :type wmsg: list
  3513. :returns: An instance of this class.
  3514. """
  3515. # this should already be verified by WampSerializer.unserialize
  3516. assert(len(wmsg) > 0 and wmsg[0] == Result.MESSAGE_TYPE)
  3517. if len(wmsg) not in (3, 4, 5):
  3518. raise ProtocolError("invalid message length {0} for RESULT".format(len(wmsg)))
  3519. request = check_or_raise_id(wmsg[1], u"'request' in RESULT")
  3520. details = check_or_raise_extra(wmsg[2], u"'details' in RESULT")
  3521. args = None
  3522. kwargs = None
  3523. payload = None
  3524. progress = None
  3525. enc_algo = None
  3526. enc_key = None
  3527. enc_serializer = None
  3528. callee = None
  3529. callee_authid = None
  3530. callee_authrole = None
  3531. forward_for = None
  3532. if len(wmsg) == 4 and type(wmsg[3]) in [six.text_type, six.binary_type]:
  3533. payload = wmsg[3]
  3534. enc_algo = details.get(u'enc_algo', None)
  3535. if enc_algo and not is_valid_enc_algo(enc_algo):
  3536. raise ProtocolError("invalid value {0} for 'enc_algo' detail in RESULT".format(enc_algo))
  3537. enc_key = details.get(u'enc_key', None)
  3538. if enc_key and type(enc_key) != six.text_type:
  3539. raise ProtocolError("invalid type {0} for 'enc_key' detail in RESULT".format(type(enc_key)))
  3540. enc_serializer = details.get(u'enc_serializer', None)
  3541. if enc_serializer and not is_valid_enc_serializer(enc_serializer):
  3542. raise ProtocolError("invalid value {0} for 'enc_serializer' detail in RESULT".format(enc_serializer))
  3543. else:
  3544. if len(wmsg) > 3:
  3545. args = wmsg[3]
  3546. if args is not None and type(args) != list:
  3547. raise ProtocolError("invalid type {0} for 'args' in RESULT".format(type(args)))
  3548. if len(wmsg) > 4:
  3549. kwargs = wmsg[4]
  3550. if type(kwargs) != dict:
  3551. raise ProtocolError("invalid type {0} for 'kwargs' in RESULT".format(type(kwargs)))
  3552. if u'progress' in details:
  3553. detail_progress = details[u'progress']
  3554. if type(detail_progress) != bool:
  3555. raise ProtocolError("invalid type {0} for 'progress' option in RESULT".format(type(detail_progress)))
  3556. progress = detail_progress
  3557. if u'callee' in details:
  3558. detail_callee = details[u'callee']
  3559. if type(detail_callee) not in six.integer_types:
  3560. raise ProtocolError("invalid type {0} for 'callee' detail in RESULT".format(type(detail_callee)))
  3561. callee = detail_callee
  3562. if u'callee_authid' in details:
  3563. detail_callee_authid = details[u'callee_authid']
  3564. if type(detail_callee_authid) != six.text_type:
  3565. raise ProtocolError("invalid type {0} for 'callee_authid' detail in RESULT".format(type(detail_callee_authid)))
  3566. callee_authid = detail_callee_authid
  3567. if u'callee_authrole' in details:
  3568. detail_callee_authrole = details[u'callee_authrole']
  3569. if type(detail_callee_authrole) != six.text_type:
  3570. raise ProtocolError("invalid type {0} for 'callee_authrole' detail in RESULT".format(type(detail_callee_authrole)))
  3571. callee_authrole = detail_callee_authrole
  3572. if u'forward_for' in details:
  3573. forward_for = details[u'forward_for']
  3574. valid = False
  3575. if type(forward_for) == list:
  3576. for ff in forward_for:
  3577. if type(ff) != dict:
  3578. break
  3579. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  3580. break
  3581. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  3582. break
  3583. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  3584. break
  3585. valid = True
  3586. if not valid:
  3587. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in RESULT")
  3588. obj = Result(request,
  3589. args=args,
  3590. kwargs=kwargs,
  3591. payload=payload,
  3592. progress=progress,
  3593. enc_algo=enc_algo,
  3594. enc_key=enc_key,
  3595. enc_serializer=enc_serializer,
  3596. callee=callee,
  3597. callee_authid=callee_authid,
  3598. callee_authrole=callee_authrole,
  3599. forward_for=forward_for)
  3600. return obj
  3601. def marshal(self):
  3602. """
  3603. Marshal this object into a raw message for subsequent serialization to bytes.
  3604. :returns: The serialized raw message.
  3605. :rtype: list
  3606. """
  3607. details = {}
  3608. if self.progress is not None:
  3609. details[u'progress'] = self.progress
  3610. if self.callee is not None:
  3611. details[u'callee'] = self.callee
  3612. if self.callee_authid is not None:
  3613. details[u'callee_authid'] = self.callee_authid
  3614. if self.callee_authrole is not None:
  3615. details[u'callee_authrole'] = self.callee_authrole
  3616. if self.forward_for is not None:
  3617. details[u'forward_for'] = self.forward_for
  3618. if self.payload:
  3619. if self.enc_algo is not None:
  3620. details[u'enc_algo'] = self.enc_algo
  3621. if self.enc_key is not None:
  3622. details[u'enc_key'] = self.enc_key
  3623. if self.enc_serializer is not None:
  3624. details[u'enc_serializer'] = self.enc_serializer
  3625. return [Result.MESSAGE_TYPE, self.request, details, self.payload]
  3626. else:
  3627. if self.kwargs:
  3628. return [Result.MESSAGE_TYPE, self.request, details, self.args, self.kwargs]
  3629. elif self.args:
  3630. return [Result.MESSAGE_TYPE, self.request, details, self.args]
  3631. else:
  3632. return [Result.MESSAGE_TYPE, self.request, details]
  3633. def __str__(self):
  3634. """
  3635. Returns string representation of this message.
  3636. """
  3637. return u"Result(request={0}, args={1}, kwargs={2}, progress={3}, enc_algo={4}, enc_key={5}, enc_serializer={6}, payload={7}, callee={8}, callee_authid={9}, callee_authrole={10}, forward_for={11})".format(self.request, self.args, self.kwargs, self.progress, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), self.callee, self.callee_authid, self.callee_authrole, self.forward_for)
  3638. class Register(Message):
  3639. """
  3640. A WAMP ``REGISTER`` message.
  3641. Format: ``[REGISTER, Request|id, Options|dict, Procedure|uri]``
  3642. """
  3643. MESSAGE_TYPE = 64
  3644. """
  3645. The WAMP message code for this type of message.
  3646. """
  3647. MATCH_EXACT = u'exact'
  3648. MATCH_PREFIX = u'prefix'
  3649. MATCH_WILDCARD = u'wildcard'
  3650. INVOKE_SINGLE = u'single'
  3651. INVOKE_FIRST = u'first'
  3652. INVOKE_LAST = u'last'
  3653. INVOKE_ROUNDROBIN = u'roundrobin'
  3654. INVOKE_RANDOM = u'random'
  3655. INVOKE_ALL = u'all'
  3656. __slots__ = (
  3657. 'request',
  3658. 'procedure',
  3659. 'match',
  3660. 'invoke',
  3661. 'concurrency',
  3662. 'force_reregister',
  3663. 'forward_for',
  3664. )
  3665. def __init__(self,
  3666. request,
  3667. procedure,
  3668. match=None,
  3669. invoke=None,
  3670. concurrency=None,
  3671. force_reregister=None,
  3672. forward_for=None):
  3673. """
  3674. :param request: The WAMP request ID of this request.
  3675. :type request: int
  3676. :param procedure: The WAMP or application URI of the RPC endpoint provided.
  3677. :type procedure: str
  3678. :param match: The procedure matching policy to be used for the registration.
  3679. :type match: str
  3680. :param invoke: The procedure invocation policy to be used for the registration.
  3681. :type invoke: str
  3682. :param concurrency: The (maximum) concurrency to be used for the registration.
  3683. :type concurrency: int
  3684. :param forward_for: When this Register is forwarded over a router-to-router link,
  3685. or via an intermediary router.
  3686. :type forward_for: list[dict]
  3687. """
  3688. assert(type(request) in six.integer_types)
  3689. assert(type(procedure) == six.text_type)
  3690. assert(match is None or type(match) == six.text_type)
  3691. assert(match is None or match in [Register.MATCH_EXACT, Register.MATCH_PREFIX, Register.MATCH_WILDCARD])
  3692. assert(invoke is None or type(invoke) == six.text_type)
  3693. assert(invoke is None or invoke in [Register.INVOKE_SINGLE, Register.INVOKE_FIRST, Register.INVOKE_LAST, Register.INVOKE_ROUNDROBIN, Register.INVOKE_RANDOM])
  3694. assert(concurrency is None or (type(concurrency) in six.integer_types and concurrency > 0))
  3695. assert force_reregister in [None, True, False]
  3696. assert(forward_for is None or type(forward_for) == list)
  3697. if forward_for:
  3698. for ff in forward_for:
  3699. assert type(ff) == dict
  3700. assert 'session' in ff and type(ff['session']) in six.integer_types
  3701. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  3702. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  3703. Message.__init__(self)
  3704. self.request = request
  3705. self.procedure = procedure
  3706. self.match = match or Register.MATCH_EXACT
  3707. self.invoke = invoke or Register.INVOKE_SINGLE
  3708. self.concurrency = concurrency
  3709. self.force_reregister = force_reregister
  3710. self.forward_for = forward_for
  3711. @staticmethod
  3712. def parse(wmsg):
  3713. """
  3714. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3715. :param wmsg: The unserialized raw message.
  3716. :type wmsg: list
  3717. :returns: An instance of this class.
  3718. """
  3719. # this should already be verified by WampSerializer.unserialize
  3720. assert(len(wmsg) > 0 and wmsg[0] == Register.MESSAGE_TYPE)
  3721. if len(wmsg) != 4:
  3722. raise ProtocolError("invalid message length {0} for REGISTER".format(len(wmsg)))
  3723. request = check_or_raise_id(wmsg[1], u"'request' in REGISTER")
  3724. options = check_or_raise_extra(wmsg[2], u"'options' in REGISTER")
  3725. match = Register.MATCH_EXACT
  3726. invoke = Register.INVOKE_SINGLE
  3727. concurrency = None
  3728. force_reregister = None
  3729. forward_for = None
  3730. if u'match' in options:
  3731. option_match = options[u'match']
  3732. if type(option_match) != six.text_type:
  3733. raise ProtocolError("invalid type {0} for 'match' option in REGISTER".format(type(option_match)))
  3734. if option_match not in [Register.MATCH_EXACT, Register.MATCH_PREFIX, Register.MATCH_WILDCARD]:
  3735. raise ProtocolError("invalid value {0} for 'match' option in REGISTER".format(option_match))
  3736. match = option_match
  3737. if match == Register.MATCH_EXACT:
  3738. allow_empty_components = False
  3739. allow_last_empty = False
  3740. elif match == Register.MATCH_PREFIX:
  3741. allow_empty_components = False
  3742. allow_last_empty = True
  3743. elif match == Register.MATCH_WILDCARD:
  3744. allow_empty_components = True
  3745. allow_last_empty = False
  3746. else:
  3747. raise Exception("logic error")
  3748. procedure = check_or_raise_uri(wmsg[3], u"'procedure' in REGISTER", allow_empty_components=allow_empty_components, allow_last_empty=allow_last_empty)
  3749. if u'invoke' in options:
  3750. option_invoke = options[u'invoke']
  3751. if type(option_invoke) != six.text_type:
  3752. raise ProtocolError("invalid type {0} for 'invoke' option in REGISTER".format(type(option_invoke)))
  3753. if option_invoke not in [Register.INVOKE_SINGLE, Register.INVOKE_FIRST, Register.INVOKE_LAST, Register.INVOKE_ROUNDROBIN, Register.INVOKE_RANDOM]:
  3754. raise ProtocolError("invalid value {0} for 'invoke' option in REGISTER".format(option_invoke))
  3755. invoke = option_invoke
  3756. if u'concurrency' in options:
  3757. options_concurrency = options[u'concurrency']
  3758. if type(options_concurrency) not in six.integer_types:
  3759. raise ProtocolError("invalid type {0} for 'concurrency' option in REGISTER".format(type(options_concurrency)))
  3760. if options_concurrency < 1:
  3761. raise ProtocolError("invalid value {0} for 'concurrency' option in REGISTER".format(options_concurrency))
  3762. concurrency = options_concurrency
  3763. options_reregister = options.get(u'force_reregister', None)
  3764. if options_reregister not in [True, False, None]:
  3765. raise ProtocolError(
  3766. "invalid type {0} for 'force_reregister option in REGISTER".format(
  3767. type(options_reregister)
  3768. )
  3769. )
  3770. if options_reregister is not None:
  3771. force_reregister = options_reregister
  3772. if u'forward_for' in options:
  3773. forward_for = options[u'forward_for']
  3774. valid = False
  3775. if type(forward_for) == list:
  3776. for ff in forward_for:
  3777. if type(ff) != dict:
  3778. break
  3779. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  3780. break
  3781. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  3782. break
  3783. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  3784. break
  3785. valid = True
  3786. if not valid:
  3787. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in REGISTER")
  3788. obj = Register(request, procedure, match=match, invoke=invoke, concurrency=concurrency,
  3789. force_reregister=force_reregister, forward_for=forward_for)
  3790. return obj
  3791. def marshal_options(self):
  3792. options = {}
  3793. if self.match and self.match != Register.MATCH_EXACT:
  3794. options[u'match'] = self.match
  3795. if self.invoke and self.invoke != Register.INVOKE_SINGLE:
  3796. options[u'invoke'] = self.invoke
  3797. if self.concurrency:
  3798. options[u'concurrency'] = self.concurrency
  3799. if self.force_reregister is not None:
  3800. options[u'force_reregister'] = self.force_reregister
  3801. if self.forward_for is not None:
  3802. options[u'forward_for'] = self.forward_for
  3803. return options
  3804. def marshal(self):
  3805. """
  3806. Marshal this object into a raw message for subsequent serialization to bytes.
  3807. :returns: The serialized raw message.
  3808. :rtype: list
  3809. """
  3810. return [Register.MESSAGE_TYPE, self.request, self.marshal_options(), self.procedure]
  3811. def __str__(self):
  3812. """
  3813. Returns string representation of this message.
  3814. """
  3815. return u"Register(request={0}, procedure={1}, match={2}, invoke={3}, concurrency={4}, force_reregister={5}, forward_for={6})".format(self.request, self.procedure, self.match, self.invoke, self.concurrency, self.force_reregister, self.forward_for)
  3816. class Registered(Message):
  3817. """
  3818. A WAMP ``REGISTERED`` message.
  3819. Format: ``[REGISTERED, REGISTER.Request|id, Registration|id]``
  3820. """
  3821. MESSAGE_TYPE = 65
  3822. """
  3823. The WAMP message code for this type of message.
  3824. """
  3825. __slots__ = (
  3826. 'request',
  3827. 'registration',
  3828. )
  3829. def __init__(self, request, registration):
  3830. """
  3831. :param request: The request ID of the original ``REGISTER`` request.
  3832. :type request: int
  3833. :param registration: The registration ID for the registered procedure (or procedure pattern).
  3834. :type registration: int
  3835. """
  3836. assert(type(request) in six.integer_types)
  3837. assert(type(registration) in six.integer_types)
  3838. Message.__init__(self)
  3839. self.request = request
  3840. self.registration = registration
  3841. @staticmethod
  3842. def parse(wmsg):
  3843. """
  3844. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3845. :param wmsg: The unserialized raw message.
  3846. :type wmsg: list
  3847. :returns: An instance of this class.
  3848. """
  3849. # this should already be verified by WampSerializer.unserialize
  3850. assert(len(wmsg) > 0 and wmsg[0] == Registered.MESSAGE_TYPE)
  3851. if len(wmsg) != 3:
  3852. raise ProtocolError("invalid message length {0} for REGISTERED".format(len(wmsg)))
  3853. request = check_or_raise_id(wmsg[1], u"'request' in REGISTERED")
  3854. registration = check_or_raise_id(wmsg[2], u"'registration' in REGISTERED")
  3855. obj = Registered(request, registration)
  3856. return obj
  3857. def marshal(self):
  3858. """
  3859. Marshal this object into a raw message for subsequent serialization to bytes.
  3860. :returns: The serialized raw message.
  3861. :rtype: list
  3862. """
  3863. return [Registered.MESSAGE_TYPE, self.request, self.registration]
  3864. def __str__(self):
  3865. """
  3866. Returns string representation of this message.
  3867. """
  3868. return u"Registered(request={0}, registration={1})".format(self.request, self.registration)
  3869. class Unregister(Message):
  3870. """
  3871. A WAMP `UNREGISTER` message.
  3872. Formats:
  3873. * ``[UNREGISTER, Request|id, REGISTERED.Registration|id]``
  3874. * ``[UNREGISTER, Request|id, REGISTERED.Registration|id, Options|dict]``
  3875. """
  3876. MESSAGE_TYPE = 66
  3877. """
  3878. The WAMP message code for this type of message.
  3879. """
  3880. __slots__ = (
  3881. 'request',
  3882. 'registration',
  3883. 'forward_for',
  3884. )
  3885. def __init__(self, request, registration, forward_for=None):
  3886. """
  3887. :param request: The WAMP request ID of this request.
  3888. :type request: int
  3889. :param registration: The registration ID for the registration to unregister.
  3890. :type registration: int
  3891. :param forward_for: When this Unregister is forwarded over a router-to-router link,
  3892. or via an intermediary router.
  3893. :type forward_for: list[dict]
  3894. """
  3895. assert(type(request) in six.integer_types)
  3896. assert(type(registration) in six.integer_types)
  3897. Message.__init__(self)
  3898. self.request = request
  3899. self.registration = registration
  3900. self.forward_for = forward_for
  3901. @staticmethod
  3902. def parse(wmsg):
  3903. """
  3904. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3905. :param wmsg: The unserialized raw message.
  3906. :type wmsg: list
  3907. :returns: An instance of this class.
  3908. """
  3909. # this should already be verified by WampSerializer.unserialize
  3910. assert(len(wmsg) > 0 and wmsg[0] == Unregister.MESSAGE_TYPE)
  3911. if len(wmsg) not in [3, 4]:
  3912. raise ProtocolError("invalid message length {0} for WAMP UNREGISTER".format(len(wmsg)))
  3913. request = check_or_raise_id(wmsg[1], u"'request' in UNREGISTER")
  3914. registration = check_or_raise_id(wmsg[2], u"'registration' in UNREGISTER")
  3915. options = None
  3916. if len(wmsg) > 3:
  3917. options = check_or_raise_extra(wmsg[3], u"'options' in UNREGISTER")
  3918. forward_for = None
  3919. if options and u'forward_for' in options:
  3920. forward_for = options[u'forward_for']
  3921. valid = False
  3922. if type(forward_for) == list:
  3923. for ff in forward_for:
  3924. if type(ff) != dict:
  3925. break
  3926. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  3927. break
  3928. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  3929. break
  3930. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  3931. break
  3932. valid = True
  3933. if not valid:
  3934. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in UNREGISTER")
  3935. obj = Unregister(request, registration, forward_for=forward_for)
  3936. return obj
  3937. def marshal(self):
  3938. """
  3939. Marshal this object into a raw message for subsequent serialization to bytes.
  3940. :returns: The serialized raw message.
  3941. :rtype: list
  3942. """
  3943. if self.forward_for:
  3944. options = {
  3945. u'forward_for': self.forward_for,
  3946. }
  3947. return [Unregister.MESSAGE_TYPE, self.request, self.registration, options]
  3948. else:
  3949. return [Unregister.MESSAGE_TYPE, self.request, self.registration]
  3950. def __str__(self):
  3951. """
  3952. Returns string representation of this message.
  3953. """
  3954. return u"Unregister(request={0}, registration={1})".format(self.request, self.registration)
  3955. class Unregistered(Message):
  3956. """
  3957. A WAMP ``UNREGISTERED`` message.
  3958. Formats:
  3959. * ``[UNREGISTERED, UNREGISTER.Request|id]``
  3960. * ``[UNREGISTERED, UNREGISTER.Request|id, Details|dict]``
  3961. """
  3962. MESSAGE_TYPE = 67
  3963. """
  3964. The WAMP message code for this type of message.
  3965. """
  3966. __slots__ = (
  3967. 'request',
  3968. 'registration',
  3969. 'reason',
  3970. )
  3971. def __init__(self, request, registration=None, reason=None):
  3972. """
  3973. :param request: The request ID of the original ``UNREGISTER`` request.
  3974. :type request: int
  3975. :param registration: If unregister was actively triggered by router, the ID
  3976. of the registration revoked.
  3977. :type registration: int or None
  3978. :param reason: The reason (an URI) for revocation.
  3979. :type reason: str or None.
  3980. """
  3981. assert(type(request) in six.integer_types)
  3982. assert(registration is None or type(registration) in six.integer_types)
  3983. assert(reason is None or type(reason) == six.text_type)
  3984. assert((request != 0 and registration is None) or (request == 0 and registration != 0))
  3985. Message.__init__(self)
  3986. self.request = request
  3987. self.registration = registration
  3988. self.reason = reason
  3989. @staticmethod
  3990. def parse(wmsg):
  3991. """
  3992. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  3993. :param wmsg: The unserialized raw message.
  3994. :type wmsg: list
  3995. :returns: An instance of this class.
  3996. """
  3997. # this should already be verified by WampSerializer.unserialize
  3998. assert(len(wmsg) > 0 and wmsg[0] == Unregistered.MESSAGE_TYPE)
  3999. if len(wmsg) not in [2, 3]:
  4000. raise ProtocolError("invalid message length {0} for UNREGISTERED".format(len(wmsg)))
  4001. request = check_or_raise_id(wmsg[1], u"'request' in UNREGISTERED")
  4002. registration = None
  4003. reason = None
  4004. if len(wmsg) > 2:
  4005. details = check_or_raise_extra(wmsg[2], u"'details' in UNREGISTERED")
  4006. if u"registration" in details:
  4007. details_registration = details[u"registration"]
  4008. if type(details_registration) not in six.integer_types:
  4009. raise ProtocolError("invalid type {0} for 'registration' detail in UNREGISTERED".format(type(details_registration)))
  4010. registration = details_registration
  4011. if u"reason" in details:
  4012. reason = check_or_raise_uri(details[u"reason"], u"'reason' in UNREGISTERED")
  4013. obj = Unregistered(request, registration, reason)
  4014. return obj
  4015. def marshal(self):
  4016. """
  4017. Marshal this object into a raw message for subsequent serialization to bytes.
  4018. :returns: The serialized raw message.
  4019. :rtype: list
  4020. """
  4021. if self.reason is not None or self.registration is not None:
  4022. details = {}
  4023. if self.reason is not None:
  4024. details[u"reason"] = self.reason
  4025. if self.registration is not None:
  4026. details[u"registration"] = self.registration
  4027. return [Unregistered.MESSAGE_TYPE, self.request, details]
  4028. else:
  4029. return [Unregistered.MESSAGE_TYPE, self.request]
  4030. def __str__(self):
  4031. """
  4032. Returns string representation of this message.
  4033. """
  4034. return u"Unregistered(request={0}, reason={1}, registration={2})".format(self.request, self.reason, self.registration)
  4035. class Invocation(Message):
  4036. """
  4037. A WAMP ``INVOCATION`` message.
  4038. Formats:
  4039. * ``[INVOCATION, Request|id, REGISTERED.Registration|id, Details|dict]``
  4040. * ``[INVOCATION, Request|id, REGISTERED.Registration|id, Details|dict, CALL.Arguments|list]``
  4041. * ``[INVOCATION, Request|id, REGISTERED.Registration|id, Details|dict, CALL.Arguments|list, CALL.ArgumentsKw|dict]``
  4042. * ``[INVOCATION, Request|id, REGISTERED.Registration|id, Details|dict, Payload|binary]``
  4043. """
  4044. MESSAGE_TYPE = 68
  4045. """
  4046. The WAMP message code for this type of message.
  4047. """
  4048. __slots__ = (
  4049. 'request',
  4050. 'registration',
  4051. 'args',
  4052. 'kwargs',
  4053. 'payload',
  4054. 'timeout',
  4055. 'receive_progress',
  4056. 'caller',
  4057. 'caller_authid',
  4058. 'caller_authrole',
  4059. 'procedure',
  4060. 'enc_algo',
  4061. 'enc_key',
  4062. 'enc_serializer',
  4063. 'forward_for',
  4064. )
  4065. def __init__(self,
  4066. request,
  4067. registration,
  4068. args=None,
  4069. kwargs=None,
  4070. payload=None,
  4071. timeout=None,
  4072. receive_progress=None,
  4073. caller=None,
  4074. caller_authid=None,
  4075. caller_authrole=None,
  4076. procedure=None,
  4077. enc_algo=None,
  4078. enc_key=None,
  4079. enc_serializer=None,
  4080. forward_for=None):
  4081. """
  4082. :param request: The WAMP request ID of this request.
  4083. :type request: int
  4084. :param registration: The registration ID of the endpoint to be invoked.
  4085. :type registration: int
  4086. :param args: Positional values for application-defined event payload.
  4087. Must be serializable using any serializers in use.
  4088. :type args: list or tuple or None
  4089. :param kwargs: Keyword values for application-defined event payload.
  4090. Must be serializable using any serializers in use.
  4091. :type kwargs: dict or None
  4092. :param payload: Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
  4093. :type payload: bytes or None
  4094. :param timeout: If present, let the callee automatically cancels
  4095. the invocation after this ms.
  4096. :type timeout: int or None
  4097. :param receive_progress: Indicates if the callee should produce progressive results.
  4098. :type receive_progress: bool or None
  4099. :param caller: The WAMP session ID of the caller. Only filled if caller is disclosed.
  4100. :type caller: None or int
  4101. :param caller_authid: The WAMP authid of the caller. Only filled if caller is disclosed.
  4102. :type caller_authid: None or unicode
  4103. :param caller_authrole: The WAMP authrole of the caller. Only filled if caller is disclosed.
  4104. :type caller_authrole: None or unicode
  4105. :param procedure: For pattern-based registrations, the invocation MUST include the actual procedure being called.
  4106. :type procedure: str or None
  4107. :param enc_algo: If using payload transparency, the encoding algorithm that was used to encode the payload.
  4108. :type enc_algo: str or None
  4109. :param enc_key: If using payload transparency with an encryption algorithm, the payload encryption key.
  4110. :type enc_key: str or None
  4111. :param enc_serializer: If using payload transparency, the payload object serializer that was used encoding the payload.
  4112. :type enc_serializer: str or None
  4113. :param forward_for: When this Call is forwarded for a client (or from an intermediary router).
  4114. :type forward_for: list[dict]
  4115. """
  4116. assert(type(request) in six.integer_types)
  4117. assert(type(registration) in six.integer_types)
  4118. assert(args is None or type(args) in [list, tuple])
  4119. assert(kwargs is None or type(kwargs) == dict)
  4120. assert(payload is None or type(payload) == six.binary_type)
  4121. assert(payload is None or (payload is not None and args is None and kwargs is None))
  4122. assert(timeout is None or type(timeout) in six.integer_types)
  4123. assert(receive_progress is None or type(receive_progress) == bool)
  4124. assert(caller is None or type(caller) in six.integer_types)
  4125. assert(caller_authid is None or type(caller_authid) == six.text_type)
  4126. assert(caller_authrole is None or type(caller_authrole) == six.text_type)
  4127. assert(procedure is None or type(procedure) == six.text_type)
  4128. assert(enc_algo is None or is_valid_enc_algo(enc_algo))
  4129. assert(enc_key is None or type(enc_key) == six.text_type)
  4130. assert(enc_serializer is None or is_valid_enc_serializer(enc_serializer))
  4131. assert((enc_algo is None and enc_key is None and enc_serializer is None) or (payload is not None and enc_algo is not None))
  4132. assert(forward_for is None or type(forward_for) == list)
  4133. if forward_for:
  4134. for ff in forward_for:
  4135. assert type(ff) == dict
  4136. assert 'session' in ff and type(ff['session']) in six.integer_types
  4137. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  4138. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  4139. Message.__init__(self)
  4140. self.request = request
  4141. self.registration = registration
  4142. self.args = args
  4143. self.kwargs = _validate_kwargs(kwargs)
  4144. self.payload = payload
  4145. self.timeout = timeout
  4146. self.receive_progress = receive_progress
  4147. self.caller = caller
  4148. self.caller_authid = caller_authid
  4149. self.caller_authrole = caller_authrole
  4150. self.procedure = procedure
  4151. self.enc_algo = enc_algo
  4152. self.enc_key = enc_key
  4153. self.enc_serializer = enc_serializer
  4154. # message forwarding
  4155. self.forward_for = forward_for
  4156. @staticmethod
  4157. def parse(wmsg):
  4158. """
  4159. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  4160. :param wmsg: The unserialized raw message.
  4161. :type wmsg: list
  4162. :returns: An instance of this class.
  4163. """
  4164. # this should already be verified by WampSerializer.unserialize
  4165. assert(len(wmsg) > 0 and wmsg[0] == Invocation.MESSAGE_TYPE)
  4166. if len(wmsg) not in (4, 5, 6):
  4167. raise ProtocolError("invalid message length {0} for INVOCATION".format(len(wmsg)))
  4168. request = check_or_raise_id(wmsg[1], u"'request' in INVOCATION")
  4169. registration = check_or_raise_id(wmsg[2], u"'registration' in INVOCATION")
  4170. details = check_or_raise_extra(wmsg[3], u"'details' in INVOCATION")
  4171. args = None
  4172. kwargs = None
  4173. payload = None
  4174. enc_algo = None
  4175. enc_key = None
  4176. enc_serializer = None
  4177. if len(wmsg) == 5 and type(wmsg[4]) == six.binary_type:
  4178. payload = wmsg[4]
  4179. enc_algo = details.get(u'enc_algo', None)
  4180. if enc_algo and not is_valid_enc_algo(enc_algo):
  4181. raise ProtocolError("invalid value {0} for 'enc_algo' detail in INVOCATION".format(enc_algo))
  4182. enc_key = details.get(u'enc_key', None)
  4183. if enc_key and type(enc_key) != six.text_type:
  4184. raise ProtocolError("invalid type {0} for 'enc_key' detail in INVOCATION".format(type(enc_key)))
  4185. enc_serializer = details.get(u'enc_serializer', None)
  4186. if enc_serializer and not is_valid_enc_serializer(enc_serializer):
  4187. raise ProtocolError("invalid value {0} for 'enc_serializer' detail in INVOCATION".format(enc_serializer))
  4188. else:
  4189. if len(wmsg) > 4:
  4190. args = wmsg[4]
  4191. if args is not None and type(args) != list:
  4192. raise ProtocolError("invalid type {0} for 'args' in INVOCATION".format(type(args)))
  4193. if len(wmsg) > 5:
  4194. kwargs = wmsg[5]
  4195. if type(kwargs) != dict:
  4196. raise ProtocolError("invalid type {0} for 'kwargs' in INVOCATION".format(type(kwargs)))
  4197. timeout = None
  4198. receive_progress = None
  4199. caller = None
  4200. caller_authid = None
  4201. caller_authrole = None
  4202. procedure = None
  4203. forward_for = None
  4204. if u'timeout' in details:
  4205. detail_timeout = details[u'timeout']
  4206. if type(detail_timeout) not in six.integer_types:
  4207. raise ProtocolError("invalid type {0} for 'timeout' detail in INVOCATION".format(type(detail_timeout)))
  4208. if detail_timeout < 0:
  4209. raise ProtocolError("invalid value {0} for 'timeout' detail in INVOCATION".format(detail_timeout))
  4210. timeout = detail_timeout
  4211. if u'receive_progress' in details:
  4212. detail_receive_progress = details[u'receive_progress']
  4213. if type(detail_receive_progress) != bool:
  4214. raise ProtocolError("invalid type {0} for 'receive_progress' detail in INVOCATION".format(type(detail_receive_progress)))
  4215. receive_progress = detail_receive_progress
  4216. if u'caller' in details:
  4217. detail_caller = details[u'caller']
  4218. if type(detail_caller) not in six.integer_types:
  4219. raise ProtocolError("invalid type {0} for 'caller' detail in INVOCATION".format(type(detail_caller)))
  4220. caller = detail_caller
  4221. if u'caller_authid' in details:
  4222. detail_caller_authid = details[u'caller_authid']
  4223. if type(detail_caller_authid) != six.text_type:
  4224. raise ProtocolError("invalid type {0} for 'caller_authid' detail in INVOCATION".format(type(detail_caller_authid)))
  4225. caller_authid = detail_caller_authid
  4226. if u'caller_authrole' in details:
  4227. detail_caller_authrole = details[u'caller_authrole']
  4228. if type(detail_caller_authrole) != six.text_type:
  4229. raise ProtocolError("invalid type {0} for 'caller_authrole' detail in INVOCATION".format(type(detail_caller_authrole)))
  4230. caller_authrole = detail_caller_authrole
  4231. if u'procedure' in details:
  4232. detail_procedure = details[u'procedure']
  4233. if type(detail_procedure) != six.text_type:
  4234. raise ProtocolError("invalid type {0} for 'procedure' detail in INVOCATION".format(type(detail_procedure)))
  4235. procedure = detail_procedure
  4236. if u'forward_for' in details:
  4237. forward_for = details[u'forward_for']
  4238. valid = False
  4239. if type(forward_for) == list:
  4240. for ff in forward_for:
  4241. if type(ff) != dict:
  4242. break
  4243. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  4244. break
  4245. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  4246. break
  4247. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  4248. break
  4249. valid = True
  4250. if not valid:
  4251. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in INVOCATION")
  4252. obj = Invocation(request,
  4253. registration,
  4254. args=args,
  4255. kwargs=kwargs,
  4256. payload=payload,
  4257. timeout=timeout,
  4258. receive_progress=receive_progress,
  4259. caller=caller,
  4260. caller_authid=caller_authid,
  4261. caller_authrole=caller_authrole,
  4262. procedure=procedure,
  4263. enc_algo=enc_algo,
  4264. enc_key=enc_key,
  4265. enc_serializer=enc_serializer,
  4266. forward_for=forward_for)
  4267. return obj
  4268. def marshal(self):
  4269. """
  4270. Marshal this object into a raw message for subsequent serialization to bytes.
  4271. :returns: The serialized raw message.
  4272. :rtype: list
  4273. """
  4274. options = {}
  4275. if self.timeout is not None:
  4276. options[u'timeout'] = self.timeout
  4277. if self.receive_progress is not None:
  4278. options[u'receive_progress'] = self.receive_progress
  4279. if self.caller is not None:
  4280. options[u'caller'] = self.caller
  4281. if self.caller_authid is not None:
  4282. options[u'caller_authid'] = self.caller_authid
  4283. if self.caller_authrole is not None:
  4284. options[u'caller_authrole'] = self.caller_authrole
  4285. if self.procedure is not None:
  4286. options[u'procedure'] = self.procedure
  4287. if self.forward_for is not None:
  4288. options[u'forward_for'] = self.forward_for
  4289. if self.payload:
  4290. if self.enc_algo is not None:
  4291. options[u'enc_algo'] = self.enc_algo
  4292. if self.enc_key is not None:
  4293. options[u'enc_key'] = self.enc_key
  4294. if self.enc_serializer is not None:
  4295. options[u'enc_serializer'] = self.enc_serializer
  4296. return [Invocation.MESSAGE_TYPE, self.request, self.registration, options, self.payload]
  4297. else:
  4298. if self.kwargs:
  4299. return [Invocation.MESSAGE_TYPE, self.request, self.registration, options, self.args, self.kwargs]
  4300. elif self.args:
  4301. return [Invocation.MESSAGE_TYPE, self.request, self.registration, options, self.args]
  4302. else:
  4303. return [Invocation.MESSAGE_TYPE, self.request, self.registration, options]
  4304. def __str__(self):
  4305. """
  4306. Returns string representation of this message.
  4307. """
  4308. return u"Invocation(request={0}, registration={1}, args={2}, kwargs={3}, timeout={4}, receive_progress={5}, caller={6}, caller_authid={7}, caller_authrole={8}, procedure={9}, enc_algo={10}, enc_key={11}, enc_serializer={12}, payload={13})".format(self.request, self.registration, self.args, self.kwargs, self.timeout, self.receive_progress, self.caller, self.caller_authid, self.caller_authrole, self.procedure, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload))
  4309. class Interrupt(Message):
  4310. """
  4311. A WAMP ``INTERRUPT`` message.
  4312. Format: ``[INTERRUPT, INVOCATION.Request|id, Options|dict]``
  4313. See: https://wamp-proto.org/static/rfc/draft-oberstet-hybi-crossbar-wamp.html#rfc.section.14.3.4
  4314. """
  4315. MESSAGE_TYPE = 69
  4316. """
  4317. The WAMP message code for this type of message.
  4318. """
  4319. KILL = u'kill'
  4320. KILLNOWAIT = u'killnowait'
  4321. __slots__ = (
  4322. 'request',
  4323. 'mode',
  4324. 'reason',
  4325. 'forward_for',
  4326. )
  4327. def __init__(self, request, mode=None, reason=None, forward_for=None):
  4328. """
  4329. :param request: The WAMP request ID of the original ``INVOCATION`` to interrupt.
  4330. :type request: int
  4331. :param mode: Specifies how to interrupt the invocation (``"killnowait"`` or ``"kill"``).
  4332. With ``"kill"``, the router will wait for the callee to return an ERROR before
  4333. proceeding (sending back an ERROR to the original caller). With ``"killnowait"`` the
  4334. router will immediately proceed (on the caller side returning an ERROR) - but still
  4335. expects the callee to send an ERROR to conclude the message exchange for the inflight
  4336. call.
  4337. :type mode: str or None
  4338. :param reason: The reason (an URI) for the invocation interrupt, eg actively
  4339. triggered by the caller (``"wamp.error.canceled"`` - ApplicationError.CANCELED) or
  4340. passively because of timeout (``"wamp.error.timeout"`` - ApplicationError.TIMEOUT).
  4341. :type reason: str or None.
  4342. :param forward_for: When this Call is forwarded for a client (or from an intermediary router).
  4343. :type forward_for: list[dict]
  4344. """
  4345. assert(type(request) in six.integer_types)
  4346. assert(mode is None or type(mode) == six.text_type)
  4347. assert(mode is None or mode in [self.KILL, self.KILLNOWAIT])
  4348. assert(reason is None or type(reason) == six.text_type)
  4349. assert(forward_for is None or type(forward_for) == list)
  4350. if forward_for:
  4351. for ff in forward_for:
  4352. assert type(ff) == dict
  4353. assert 'session' in ff and type(ff['session']) in six.integer_types
  4354. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  4355. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  4356. Message.__init__(self)
  4357. self.request = request
  4358. self.mode = mode
  4359. self.reason = reason
  4360. # message forwarding
  4361. self.forward_for = forward_for
  4362. @staticmethod
  4363. def parse(wmsg):
  4364. """
  4365. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  4366. :param wmsg: The unserialized raw message.
  4367. :type wmsg: list
  4368. :returns: An instance of this class.
  4369. """
  4370. # this should already be verified by WampSerializer.unserialize
  4371. assert(len(wmsg) > 0 and wmsg[0] == Interrupt.MESSAGE_TYPE)
  4372. if len(wmsg) != 3:
  4373. raise ProtocolError("invalid message length {0} for INTERRUPT".format(len(wmsg)))
  4374. request = check_or_raise_id(wmsg[1], u"'request' in INTERRUPT")
  4375. options = check_or_raise_extra(wmsg[2], u"'options' in INTERRUPT")
  4376. # options
  4377. #
  4378. mode = None
  4379. reason = None
  4380. forward_for = None
  4381. if u'mode' in options:
  4382. option_mode = options[u'mode']
  4383. if type(option_mode) != six.text_type:
  4384. raise ProtocolError("invalid type {0} for 'mode' option in INTERRUPT".format(type(option_mode)))
  4385. if option_mode not in [Interrupt.KILL, Interrupt.KILLNOWAIT]:
  4386. raise ProtocolError("invalid value '{0}' for 'mode' option in INTERRUPT".format(option_mode))
  4387. mode = option_mode
  4388. if u'reason' in options:
  4389. reason = check_or_raise_uri(options[u'reason'], u'"reason" in INTERRUPT')
  4390. if u'forward_for' in options:
  4391. forward_for = options[u'forward_for']
  4392. valid = False
  4393. if type(forward_for) == list:
  4394. for ff in forward_for:
  4395. if type(ff) != dict:
  4396. break
  4397. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  4398. break
  4399. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  4400. break
  4401. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  4402. break
  4403. valid = True
  4404. if not valid:
  4405. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in INTERRUPT")
  4406. obj = Interrupt(request, mode=mode, reason=reason, forward_for=forward_for)
  4407. return obj
  4408. def marshal(self):
  4409. """
  4410. Marshal this object into a raw message for subsequent serialization to bytes.
  4411. :returns: The serialized raw message.
  4412. :rtype: list
  4413. """
  4414. options = {}
  4415. if self.mode is not None:
  4416. options[u'mode'] = self.mode
  4417. if self.reason is not None:
  4418. options[u'reason'] = self.reason
  4419. if self.forward_for is not None:
  4420. options[u'forward_for'] = self.forward_for
  4421. return [Interrupt.MESSAGE_TYPE, self.request, options]
  4422. def __str__(self):
  4423. """
  4424. Returns string representation of this message.
  4425. """
  4426. return u"Interrupt(request={0}, mode={1}, reason={2})".format(self.request, self.mode, self.reason)
  4427. class Yield(Message):
  4428. """
  4429. A WAMP ``YIELD`` message.
  4430. Formats:
  4431. * ``[YIELD, INVOCATION.Request|id, Options|dict]``
  4432. * ``[YIELD, INVOCATION.Request|id, Options|dict, Arguments|list]``
  4433. * ``[YIELD, INVOCATION.Request|id, Options|dict, Arguments|list, ArgumentsKw|dict]``
  4434. * ``[YIELD, INVOCATION.Request|id, Options|dict, Payload|binary]``
  4435. """
  4436. MESSAGE_TYPE = 70
  4437. """
  4438. The WAMP message code for this type of message.
  4439. """
  4440. __slots__ = (
  4441. 'request',
  4442. 'args',
  4443. 'kwargs',
  4444. 'payload',
  4445. 'progress',
  4446. 'enc_algo',
  4447. 'enc_key',
  4448. 'enc_serializer',
  4449. 'callee',
  4450. 'callee_authid',
  4451. 'callee_authrole',
  4452. 'forward_for',
  4453. )
  4454. def __init__(self,
  4455. request,
  4456. args=None,
  4457. kwargs=None,
  4458. payload=None,
  4459. progress=None,
  4460. enc_algo=None,
  4461. enc_key=None,
  4462. enc_serializer=None,
  4463. callee=None,
  4464. callee_authid=None,
  4465. callee_authrole=None,
  4466. forward_for=None):
  4467. """
  4468. :param request: The WAMP request ID of the original call.
  4469. :type request: int
  4470. :param args: Positional values for application-defined event payload.
  4471. Must be serializable using any serializers in use.
  4472. :type args: list or tuple or None
  4473. :param kwargs: Keyword values for application-defined event payload.
  4474. Must be serializable using any serializers in use.
  4475. :type kwargs: dict or None
  4476. :param payload: Alternative, transparent payload. If given, ``args`` and ``kwargs`` must be left unset.
  4477. :type payload: bytes or None
  4478. :param progress: If ``True``, this result is a progressive invocation result, and subsequent
  4479. results (or a final error) will follow.
  4480. :type progress: bool or None
  4481. :param enc_algo: If using payload transparency, the encoding algorithm that was used to encode the payload.
  4482. :type enc_algo: str or None
  4483. :param enc_key: If using payload transparency with an encryption algorithm, the payload encryption key.
  4484. :type enc_key: str or None
  4485. :param enc_serializer: If using payload transparency, the payload object serializer that was used encoding the payload.
  4486. :type enc_serializer: str or None
  4487. :param callee: The WAMP session ID of the effective callee that responded with the error. Only filled if callee is disclosed.
  4488. :type callee: None or int
  4489. :param callee_authid: The WAMP authid of the responding callee. Only filled if callee is disclosed.
  4490. :type callee_authid: None or unicode
  4491. :param callee_authrole: The WAMP authrole of the responding callee. Only filled if callee is disclosed.
  4492. :type callee_authrole: None or unicode
  4493. :param forward_for: When this Call is forwarded for a client (or from an intermediary router).
  4494. :type forward_for: list[dict]
  4495. """
  4496. assert(type(request) in six.integer_types)
  4497. assert(args is None or type(args) in [list, tuple])
  4498. assert(kwargs is None or type(kwargs) == dict)
  4499. assert(payload is None or type(payload) == six.binary_type)
  4500. assert(payload is None or (payload is not None and args is None and kwargs is None))
  4501. assert(progress is None or type(progress) == bool)
  4502. assert(enc_algo is None or is_valid_enc_algo(enc_algo))
  4503. assert((enc_algo is None and enc_key is None and enc_serializer is None) or (payload is not None and enc_algo is not None))
  4504. assert(enc_key is None or type(enc_key) == six.text_type)
  4505. assert(enc_serializer is None or is_valid_enc_serializer(enc_serializer))
  4506. assert(callee is None or type(callee) in six.integer_types)
  4507. assert(callee_authid is None or type(callee_authid) == six.text_type)
  4508. assert(callee_authrole is None or type(callee_authrole) == six.text_type)
  4509. assert(forward_for is None or type(forward_for) == list)
  4510. if forward_for:
  4511. for ff in forward_for:
  4512. assert type(ff) == dict
  4513. assert 'session' in ff and type(ff['session']) in six.integer_types
  4514. assert 'authid' in ff and (ff['authid'] is None or type(ff['authid']) == six.text_type)
  4515. assert 'authrole' in ff and type(ff['authrole']) == six.text_type
  4516. Message.__init__(self)
  4517. self.request = request
  4518. self.args = args
  4519. self.kwargs = _validate_kwargs(kwargs)
  4520. self.payload = payload
  4521. self.progress = progress
  4522. self.enc_algo = enc_algo
  4523. self.enc_key = enc_key
  4524. self.enc_serializer = enc_serializer
  4525. # effective callee that responded with the result
  4526. self.callee = callee
  4527. self.callee_authid = callee_authid
  4528. self.callee_authrole = callee_authrole
  4529. # message forwarding
  4530. self.forward_for = forward_for
  4531. @staticmethod
  4532. def parse(wmsg):
  4533. """
  4534. Verifies and parses an unserialized raw message into an actual WAMP message instance.
  4535. :param wmsg: The unserialized raw message.
  4536. :type wmsg: list
  4537. :returns: An instance of this class.
  4538. """
  4539. # this should already be verified by WampSerializer.unserialize
  4540. assert(len(wmsg) > 0 and wmsg[0] == Yield.MESSAGE_TYPE)
  4541. if len(wmsg) not in (3, 4, 5):
  4542. raise ProtocolError("invalid message length {0} for YIELD".format(len(wmsg)))
  4543. request = check_or_raise_id(wmsg[1], u"'request' in YIELD")
  4544. options = check_or_raise_extra(wmsg[2], u"'options' in YIELD")
  4545. args = None
  4546. kwargs = None
  4547. payload = None
  4548. enc_algo = None
  4549. enc_key = None
  4550. enc_serializer = None
  4551. if len(wmsg) == 4 and type(wmsg[3]) == six.binary_type:
  4552. payload = wmsg[3]
  4553. enc_algo = options.get(u'enc_algo', None)
  4554. if enc_algo and not is_valid_enc_algo(enc_algo):
  4555. raise ProtocolError("invalid value {0} for 'enc_algo' detail in YIELD".format(enc_algo))
  4556. enc_key = options.get(u'enc_key', None)
  4557. if enc_key and type(enc_key) != six.text_type:
  4558. raise ProtocolError("invalid type {0} for 'enc_key' detail in YIELD".format(type(enc_key)))
  4559. enc_serializer = options.get(u'enc_serializer', None)
  4560. if enc_serializer and not is_valid_enc_serializer(enc_serializer):
  4561. raise ProtocolError("invalid value {0} for 'enc_serializer' detail in YIELD".format(enc_serializer))
  4562. else:
  4563. if len(wmsg) > 3:
  4564. args = wmsg[3]
  4565. if args is not None and type(args) != list:
  4566. raise ProtocolError("invalid type {0} for 'args' in YIELD".format(type(args)))
  4567. if len(wmsg) > 4:
  4568. kwargs = wmsg[4]
  4569. if type(kwargs) != dict:
  4570. raise ProtocolError("invalid type {0} for 'kwargs' in YIELD".format(type(kwargs)))
  4571. progress = None
  4572. callee = None
  4573. callee_authid = None
  4574. callee_authrole = None
  4575. forward_for = None
  4576. if u'progress' in options:
  4577. option_progress = options[u'progress']
  4578. if type(option_progress) != bool:
  4579. raise ProtocolError("invalid type {0} for 'progress' option in YIELD".format(type(option_progress)))
  4580. progress = option_progress
  4581. if u'callee' in options:
  4582. option_callee = options[u'callee']
  4583. if type(option_callee) not in six.integer_types:
  4584. raise ProtocolError("invalid type {0} for 'callee' detail in YIELD".format(type(option_callee)))
  4585. callee = option_callee
  4586. if u'callee_authid' in options:
  4587. option_callee_authid = options[u'callee_authid']
  4588. if type(option_callee_authid) != six.text_type:
  4589. raise ProtocolError("invalid type {0} for 'callee_authid' detail in YIELD".format(type(option_callee_authid)))
  4590. callee_authid = option_callee_authid
  4591. if u'callee_authrole' in options:
  4592. option_callee_authrole = options[u'callee_authrole']
  4593. if type(option_callee_authrole) != six.text_type:
  4594. raise ProtocolError("invalid type {0} for 'callee_authrole' detail in YIELD".format(type(option_callee_authrole)))
  4595. callee_authrole = option_callee_authrole
  4596. if u'forward_for' in options:
  4597. forward_for = options[u'forward_for']
  4598. valid = False
  4599. if type(forward_for) == list:
  4600. for ff in forward_for:
  4601. if type(ff) != dict:
  4602. break
  4603. if 'session' not in ff or type(ff['session']) not in six.integer_types:
  4604. break
  4605. if 'authid' not in ff or type(ff['authid']) != six.text_type:
  4606. break
  4607. if 'authrole' not in ff or type(ff['authrole']) != six.text_type:
  4608. break
  4609. valid = True
  4610. if not valid:
  4611. raise ProtocolError("invalid type/value {0} for/within 'forward_for' option in YIELD")
  4612. obj = Yield(request,
  4613. args=args,
  4614. kwargs=kwargs,
  4615. payload=payload,
  4616. progress=progress,
  4617. enc_algo=enc_algo,
  4618. enc_key=enc_key,
  4619. enc_serializer=enc_serializer,
  4620. callee=callee,
  4621. callee_authid=callee_authid,
  4622. callee_authrole=callee_authrole,
  4623. forward_for=forward_for)
  4624. return obj
  4625. def marshal(self):
  4626. """
  4627. Marshal this object into a raw message for subsequent serialization to bytes.
  4628. :returns: The serialized raw message.
  4629. :rtype: list
  4630. """
  4631. options = {}
  4632. if self.progress is not None:
  4633. options[u'progress'] = self.progress
  4634. if self.callee is not None:
  4635. options[u'callee'] = self.callee
  4636. if self.callee_authid is not None:
  4637. options[u'callee_authid'] = self.callee_authid
  4638. if self.callee_authrole is not None:
  4639. options[u'callee_authrole'] = self.callee_authrole
  4640. if self.forward_for is not None:
  4641. options[u'forward_for'] = self.forward_for
  4642. if self.payload:
  4643. if self.enc_algo is not None:
  4644. options[u'enc_algo'] = self.enc_algo
  4645. if self.enc_key is not None:
  4646. options[u'enc_key'] = self.enc_key
  4647. if self.enc_serializer is not None:
  4648. options[u'enc_serializer'] = self.enc_serializer
  4649. return [Yield.MESSAGE_TYPE, self.request, options, self.payload]
  4650. else:
  4651. if self.kwargs:
  4652. return [Yield.MESSAGE_TYPE, self.request, options, self.args, self.kwargs]
  4653. elif self.args:
  4654. return [Yield.MESSAGE_TYPE, self.request, options, self.args]
  4655. else:
  4656. return [Yield.MESSAGE_TYPE, self.request, options]
  4657. def __str__(self):
  4658. """
  4659. Returns string representation of this message.
  4660. """
  4661. return u"Yield(request={0}, args={1}, kwargs={2}, progress={3}, enc_algo={4}, enc_key={5}, enc_serializer={6}, payload={7}, callee={8}, callee_authid={9}, callee_authrole={10}, forward_for={11})".format(self.request, self.args, self.kwargs, self.progress, self.enc_algo, self.enc_key, self.enc_serializer, b2a(self.payload), self.callee, self.callee_authid, self.callee_authrole, self.forward_for)