synapse 2.155.0__py311-none-any.whl → 2.156.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (64) hide show
  1. synapse/cmds/cortex.py +2 -14
  2. synapse/common.py +1 -28
  3. synapse/cortex.py +10 -510
  4. synapse/lib/ast.py +60 -1
  5. synapse/lib/cell.py +33 -8
  6. synapse/lib/certdir.py +11 -0
  7. synapse/lib/cmdr.py +0 -5
  8. synapse/lib/gis.py +2 -2
  9. synapse/lib/httpapi.py +1 -43
  10. synapse/lib/layer.py +64 -201
  11. synapse/lib/lmdbslab.py +11 -0
  12. synapse/lib/node.py +1 -3
  13. synapse/lib/parser.py +10 -0
  14. synapse/lib/snap.py +121 -21
  15. synapse/lib/storm.lark +23 -6
  16. synapse/lib/storm.py +15 -338
  17. synapse/lib/storm_format.py +5 -0
  18. synapse/lib/stormlib/gen.py +1 -2
  19. synapse/lib/stormlib/gis.py +41 -0
  20. synapse/lib/stormlib/stats.py +21 -2
  21. synapse/lib/stormlib/storm.py +16 -1
  22. synapse/lib/stormtypes.py +225 -12
  23. synapse/lib/version.py +2 -2
  24. synapse/lib/view.py +96 -21
  25. synapse/models/inet.py +60 -30
  26. synapse/models/infotech.py +56 -1
  27. synapse/models/orgs.py +3 -0
  28. synapse/models/risk.py +15 -0
  29. synapse/models/syn.py +0 -38
  30. synapse/tests/test_cmds_cortex.py +1 -1
  31. synapse/tests/test_cortex.py +32 -336
  32. synapse/tests/test_lib_agenda.py +19 -54
  33. synapse/tests/test_lib_aha.py +97 -0
  34. synapse/tests/test_lib_ast.py +402 -0
  35. synapse/tests/test_lib_grammar.py +30 -10
  36. synapse/tests/test_lib_httpapi.py +0 -46
  37. synapse/tests/test_lib_layer.py +19 -234
  38. synapse/tests/test_lib_lmdbslab.py +22 -0
  39. synapse/tests/test_lib_snap.py +9 -0
  40. synapse/tests/test_lib_storm.py +16 -309
  41. synapse/tests/test_lib_stormlib_gis.py +21 -0
  42. synapse/tests/test_lib_stormlib_stats.py +107 -20
  43. synapse/tests/test_lib_stormlib_storm.py +25 -0
  44. synapse/tests/test_lib_stormtypes.py +231 -8
  45. synapse/tests/test_lib_view.py +6 -13
  46. synapse/tests/test_model_base.py +1 -1
  47. synapse/tests/test_model_inet.py +15 -0
  48. synapse/tests/test_model_infotech.py +60 -0
  49. synapse/tests/test_model_orgs.py +10 -0
  50. synapse/tests/test_model_person.py +0 -3
  51. synapse/tests/test_model_risk.py +20 -0
  52. synapse/tests/test_model_syn.py +20 -34
  53. synapse/tests/test_tools_csvtool.py +2 -1
  54. synapse/tests/test_tools_feed.py +4 -30
  55. synapse/tools/csvtool.py +2 -1
  56. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/METADATA +3 -3
  57. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/RECORD +60 -62
  58. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/WHEEL +1 -1
  59. synapse/cmds/cron.py +0 -726
  60. synapse/cmds/trigger.py +0 -319
  61. synapse/tests/test_cmds_cron.py +0 -453
  62. synapse/tests/test_cmds_trigger.py +0 -176
  63. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/LICENSE +0 -0
  64. {synapse-2.155.0.dist-info → synapse-2.156.0.dist-info}/top_level.txt +0 -0
synapse/lib/ast.py CHANGED
@@ -696,6 +696,9 @@ class SubQuery(Oper):
696
696
  if len(kids):
697
697
  self.text = kids[0].getAstText()
698
698
 
699
+ def isRuntSafe(self, runt):
700
+ return True
701
+
699
702
  async def run(self, runt, genr):
700
703
 
701
704
  subq = self.kids[0]
@@ -804,6 +807,38 @@ class InitBlock(AstNode):
804
807
  async for innr in subq.run(runt, s_common.agen()):
805
808
  yield innr
806
809
 
810
+ class EmptyBlock(AstNode):
811
+ '''
812
+ An AST node that only runs if there are not inbound nodes in the pipeline. It is
813
+ capable of yielding nodes into the pipeline.
814
+
815
+ Example:
816
+
817
+ Using an empty block::
818
+
819
+ empty {
820
+ // the pipeline is empty so this block will execute
821
+ }
822
+
823
+ [foo:bar=*]
824
+ empty {
825
+ // there is a node in the pipeline so this block will not run
826
+ }
827
+ '''
828
+ async def run(self, runt, genr):
829
+
830
+ subq = self.kids[0]
831
+ self.reqRuntSafe(runt, 'Empty block query must be runtsafe')
832
+
833
+ empty = True
834
+ async for item in genr:
835
+ empty = False
836
+ yield item
837
+
838
+ if empty:
839
+ async for subn in subq.run(runt, s_common.agen()):
840
+ yield subn
841
+
807
842
  class FiniBlock(AstNode):
808
843
  '''
809
844
  An AST node that runs only once after all nodes have been consumed.
@@ -856,7 +891,7 @@ class TryCatch(AstNode):
856
891
  async for subi in block.run(runt, agen):
857
892
  yield subi
858
893
 
859
- if count == 0 and self.isRuntSafe(runt):
894
+ if count == 0:
860
895
  try:
861
896
  async for item in self.kids[0].run(runt, genr):
862
897
  yield item
@@ -1866,6 +1901,9 @@ class N1WalkNPivo(PivotOut):
1866
1901
 
1867
1902
  async for node, path in genr:
1868
1903
 
1904
+ if self.isjoin:
1905
+ yield node, path
1906
+
1869
1907
  async for item in self.getPivsOut(runt, node, path):
1870
1908
  yield item
1871
1909
 
@@ -1985,6 +2023,9 @@ class N2WalkNPivo(PivotIn):
1985
2023
 
1986
2024
  async for node, path in genr:
1987
2025
 
2026
+ if self.isjoin:
2027
+ yield node, path
2028
+
1988
2029
  async for item in self.getPivsIn(runt, node, path):
1989
2030
  yield item
1990
2031
 
@@ -3028,6 +3069,10 @@ class PropValue(Value):
3028
3069
  name=name, form=path.node.form.name))
3029
3070
 
3030
3071
  valu = path.node.get(name)
3072
+ if isinstance(valu, (dict, list, tuple)):
3073
+ # these get special cased because changing them affects the node
3074
+ # while it's in the pipeline but the modification doesn't get stored
3075
+ valu = s_msgpack.deepcopy(valu)
3031
3076
  return prop, valu
3032
3077
 
3033
3078
  # handle implicit pivot properties
@@ -3049,6 +3094,10 @@ class PropValue(Value):
3049
3094
  name=name, form=node.form.name))
3050
3095
 
3051
3096
  if i >= imax:
3097
+ if isinstance(valu, (dict, list, tuple)):
3098
+ # these get special cased because changing them affects the node
3099
+ # while it's in the pipeline but the modification doesn't get stored
3100
+ valu = s_msgpack.deepcopy(valu)
3052
3101
  return prop, valu
3053
3102
 
3054
3103
  form = runt.model.forms.get(prop.type.name)
@@ -3900,6 +3949,13 @@ class EditUnivDel(Edit):
3900
3949
 
3901
3950
  class N1Walk(Oper):
3902
3951
 
3952
+ def __init__(self, astinfo, kids=(), isjoin=False):
3953
+ Oper.__init__(self, astinfo, kids=kids)
3954
+ self.isjoin = isjoin
3955
+
3956
+ def repr(self):
3957
+ return f'{self.__class__.__name__}: {self.kids}, isjoin={self.isjoin}'
3958
+
3903
3959
  async def walkNodeEdges(self, runt, node, verb=None):
3904
3960
  async for _, iden in node.iterEdgesN1(verb=verb):
3905
3961
  buid = s_common.uhex(iden)
@@ -3958,6 +4014,9 @@ class N1Walk(Oper):
3958
4014
 
3959
4015
  async for node, path in genr:
3960
4016
 
4017
+ if self.isjoin:
4018
+ yield node, path
4019
+
3961
4020
  verbs = await self.kids[0].compute(runt, path)
3962
4021
  verbs = await s_stormtypes.toprim(verbs)
3963
4022
 
synapse/lib/cell.py CHANGED
@@ -3420,20 +3420,45 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
3420
3420
  ahaname = provconf.get('aha:name')
3421
3421
  ahanetw = provconf.get('aha:network')
3422
3422
 
3423
- if not certdir.getCaCertPath(ahanetw):
3424
- certdir.saveCaCertByts(await prov.getCaCert())
3423
+ _crt = certdir.getCaCertPath(ahanetw)
3424
+ if _crt:
3425
+ logger.debug(f'Removing existing CA crt: {_crt}')
3426
+ os.unlink(_crt)
3427
+ certdir.saveCaCertByts(await prov.getCaCert())
3425
3428
 
3426
3429
  await self._bootProvConf(provconf)
3427
3430
 
3428
3431
  hostname = f'{ahaname}.{ahanetw}'
3429
- if certdir.getHostCertPath(hostname) is None:
3430
- hostcsr = certdir.genHostCsr(hostname)
3431
- certdir.saveHostCertByts(await prov.signHostCsr(hostcsr))
3432
+ _crt = certdir.getHostCertPath(hostname)
3433
+ if _crt:
3434
+ logger.debug(f'Removing existing host crt {_crt}')
3435
+ os.unlink(_crt)
3436
+ _kp = certdir.getHostKeyPath(hostname)
3437
+ if _kp:
3438
+ logger.debug(f'Removing existing host key {_kp}')
3439
+ os.unlink(_kp)
3440
+ _csr = certdir.getHostCsrPath(hostname)
3441
+ if _csr:
3442
+ logger.debug(f'Removing existing host csr {_csr}')
3443
+ os.unlink(_csr)
3444
+ hostcsr = certdir.genHostCsr(hostname)
3445
+ certdir.saveHostCertByts(await prov.signHostCsr(hostcsr))
3432
3446
 
3433
3447
  userfull = f'{ahauser}@{ahanetw}'
3434
- if certdir.getUserCertPath(userfull) is None:
3435
- usercsr = certdir.genUserCsr(userfull)
3436
- certdir.saveUserCertByts(await prov.signUserCsr(usercsr))
3448
+ _crt = certdir.getUserCertPath(userfull)
3449
+ if _crt:
3450
+ logger.debug(f'Removing existing user crt {_crt}')
3451
+ os.unlink(_crt)
3452
+ _kp = certdir.getUserKeyPath(userfull)
3453
+ if _kp:
3454
+ logger.debug(f'Removing existing user key {_kp}')
3455
+ os.unlink(_kp)
3456
+ _csr = certdir.getUserCsrPath(userfull)
3457
+ if _csr:
3458
+ logger.debug(f'Removing existing user csr {_csr}')
3459
+ os.unlink(_csr)
3460
+ usercsr = certdir.genUserCsr(userfull)
3461
+ certdir.saveUserCertByts(await prov.signUserCsr(usercsr))
3437
3462
 
3438
3463
  with s_common.genfile(self.dirn, 'prov.done') as fd:
3439
3464
  fd.write(providen.encode())
synapse/lib/certdir.py CHANGED
@@ -944,6 +944,17 @@ class CertDir:
944
944
  if os.path.isfile(path):
945
945
  return path
946
946
 
947
+ def getUserCsrPath(self, name):
948
+ for cdir in self.certdirs:
949
+ path = s_common.genpath(cdir, 'users', '%s.csr' % name)
950
+ if os.path.isfile(path):
951
+ return path
952
+
953
+ def getHostCsrPath(self, name):
954
+ for cdir in self.certdirs:
955
+ path = s_common.genpath(cdir, 'hosts', '%s.csr' % name)
956
+ if os.path.isfile(path):
957
+ return path
947
958
  def importFile(self, path, mode, outp=None):
948
959
  '''
949
960
  Imports certs and keys into the Synapse cert directory
synapse/lib/cmdr.py CHANGED
@@ -1,10 +1,8 @@
1
1
  import synapse.lib.cli as s_cli
2
2
 
3
3
  import synapse.cmds.boss as s_cmds_boss
4
- import synapse.cmds.cron as s_cmds_cron
5
4
  import synapse.cmds.hive as s_cmds_hive
6
5
  import synapse.cmds.cortex as s_cmds_cortex
7
- import synapse.cmds.trigger as s_cmds_trigger
8
6
 
9
7
  cmdsbycell = {
10
8
  'cell': (
@@ -14,14 +12,11 @@ cmdsbycell = {
14
12
  ),
15
13
 
16
14
  'cortex': (
17
- s_cmds_cron.At,
18
- s_cmds_cron.Cron,
19
15
  s_cmds_cortex.Log,
20
16
  s_cmds_boss.PsCmd,
21
17
  s_cmds_boss.KillCmd,
22
18
  s_cmds_hive.HiveCmd,
23
19
  s_cmds_cortex.StormCmd,
24
- s_cmds_trigger.Trigger,
25
20
  ),
26
21
  }
27
22
 
synapse/lib/gis.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import math
2
2
 
3
3
  '''
4
- Synapse module with helpers for earth based geo-spacial calculations.
4
+ Synapse module with helpers for earth based geospatial calculations.
5
5
  '''
6
6
 
7
7
  # base earth geo distances will be in mm
@@ -66,7 +66,7 @@ def haversine(px, py, r=r_mm):
66
66
 
67
67
  def bbox(lat, lon, dist):
68
68
  '''
69
- Calculate a min/max bounding box for the circle defined by lalo/dist.
69
+ Calculate a min/max bounding box for the circle defined by lat/lon/dist.
70
70
 
71
71
  Args:
72
72
  lat (float): The latitude in degrees
synapse/lib/httpapi.py CHANGED
@@ -518,7 +518,7 @@ class StormV1(StormHandler):
518
518
  if opts is None:
519
519
  return
520
520
 
521
- opts.setdefault('editformat', 'splices')
521
+ opts.setdefault('editformat', 'nodeedits')
522
522
 
523
523
  async for mesg in self.getCore().storm(query, opts=opts):
524
524
  self.write(json.dumps(mesg))
@@ -612,48 +612,6 @@ class ReqValidStormV1(StormHandler):
612
612
  else:
613
613
  return self.sendRestRetn(valid)
614
614
 
615
- class WatchSockV1(WebSocket):
616
- '''
617
- A web-socket based API endpoint for distributing cortex tag events.
618
-
619
- Deprecated.
620
- '''
621
- async def onWatchMesg(self, byts):
622
- # Note: This API handler is intended to be used on a heavy Cortex object.
623
- try:
624
-
625
- wdef = json.loads(byts)
626
- iden = wdef.get('view', self.cell.view.iden)
627
-
628
- perm = ('watch', 'view', iden)
629
- await self._reqUserAllow(perm)
630
-
631
- async with self.cell.watcher(wdef) as watcher:
632
-
633
- await self.xmit('init')
634
-
635
- async for mesg in watcher:
636
- await self.xmit(mesg[0], **mesg[1])
637
-
638
- # pragma: no cover
639
- # (this would only happen on slow-consumer)
640
- await self.xmit('fini')
641
-
642
- except s_exc.SynErr as e:
643
-
644
- text = e.get('mesg', str(e))
645
- await self.xmit('errx', code=e.__class__.__name__, mesg=text)
646
-
647
- except asyncio.CancelledError: # pragma: no cover TODO: remove once >= py 3.8 only
648
- raise
649
-
650
- except Exception as e:
651
- await self.xmit('errx', code=e.__class__.__name__, mesg=str(e))
652
-
653
- async def on_message(self, byts):
654
- s_common.deprdate('/api/v1/watch HTTP API', s_common._splicedepr)
655
- self.cell.schedCoro(self.onWatchMesg(byts))
656
-
657
615
  class BeholdSockV1(WebSocket):
658
616
 
659
617
  async def onInitMessage(self, byts):
synapse/lib/layer.py CHANGED
@@ -170,19 +170,6 @@ class LayerApi(s_cell.CellApi):
170
170
  async for item in self.layr.syncNodeEdits2(offs, wait=wait):
171
171
  yield item
172
172
 
173
- async def splices(self, offs=None, size=None):
174
- '''
175
- This API is deprecated.
176
-
177
- Yield (offs, splice) tuples from the nodeedit log starting from the given offset.
178
-
179
- Nodeedits will be flattened into splices before being yielded.
180
- '''
181
- s_common.deprdate('Layer.splices() telepath API', s_common._splicedepr)
182
- await self._reqUserAllowed(self.liftperm)
183
- async for item in self.layr.splices(offs=offs, size=size):
184
- yield item
185
-
186
173
  async def getEditIndx(self):
187
174
  '''
188
175
  Returns what will be the *next* nodeedit log index.
@@ -2023,17 +2010,14 @@ class Layer(s_nexus.Pusher):
2023
2010
  ret['totalsize'] = await self.getLayerSize()
2024
2011
  return ret
2025
2012
 
2026
- async def truncate(self):
2027
- self._reqNotReadOnly()
2028
- return await self._push('layer:truncate')
2029
-
2030
2013
  @s_nexus.Pusher.onPush('layer:truncate')
2031
2014
  async def _truncate(self):
2032
2015
  '''
2033
2016
  Nuke all the contents in the layer, leaving an empty layer
2034
2017
  NOTE: This internal API is deprecated but is kept for Nexus event backward compatibility
2035
2018
  '''
2036
- s_common.deprdate('Layer.truncate() API', s_common._splicedepr)
2019
+ # TODO: Remove this in 3.0.0
2020
+ s_common.deprecated('layer:truncate Nexus handler', curv='2.156.0')
2037
2021
 
2038
2022
  self.dirty.clear()
2039
2023
  self.buidcache.clear()
@@ -2044,8 +2028,6 @@ class Layer(s_nexus.Pusher):
2044
2028
 
2045
2029
  await self._initLayerStorage()
2046
2030
 
2047
- # async def wipe(self, meta): ...
2048
-
2049
2031
  async def iterWipeNodeEdits(self):
2050
2032
 
2051
2033
  await self._saveDirtySodes()
@@ -2914,6 +2896,7 @@ class Layer(s_nexus.Pusher):
2914
2896
  abrv = self.tagabrv.bytsToAbrv(tagname.encode())
2915
2897
  if formname is not None:
2916
2898
  abrv += self.getPropAbrv(formname, None)
2899
+ return self.layrslab.count(abrv, db=self.bytag)
2917
2900
 
2918
2901
  except s_exc.NoSuchAbrv:
2919
2902
  return 0
@@ -2931,6 +2914,44 @@ class Layer(s_nexus.Pusher):
2931
2914
 
2932
2915
  return await self.layrslab.countByPref(abrv, db=self.byprop, maxsize=maxsize)
2933
2916
 
2917
+ def getPropValuCount(self, formname, propname, stortype, valu):
2918
+ try:
2919
+ abrv = self.getPropAbrv(formname, propname)
2920
+ except s_exc.NoSuchAbrv:
2921
+ return 0
2922
+
2923
+ if stortype & 0x8000:
2924
+ stortype = STOR_TYPE_MSGP
2925
+
2926
+ count = 0
2927
+ for indx in self.getStorIndx(stortype, valu):
2928
+ count += self.layrslab.count(abrv + indx, db=self.byprop)
2929
+
2930
+ return count
2931
+
2932
+ async def getPropArrayCount(self, formname, propname=None):
2933
+ '''
2934
+ Return the number of invidiual value rows in the layer for the given array form/prop.
2935
+ '''
2936
+ try:
2937
+ abrv = self.getPropAbrv(formname, propname)
2938
+ except s_exc.NoSuchAbrv:
2939
+ return 0
2940
+
2941
+ return await self.layrslab.countByPref(abrv, db=self.byarray)
2942
+
2943
+ def getPropArrayValuCount(self, formname, propname, stortype, valu):
2944
+ try:
2945
+ abrv = self.getPropAbrv(formname, propname)
2946
+ except s_exc.NoSuchAbrv:
2947
+ return 0
2948
+
2949
+ count = 0
2950
+ for indx in self.getStorIndx(stortype, valu):
2951
+ count += self.layrslab.count(abrv + indx, db=self.byarray)
2952
+
2953
+ return count
2954
+
2934
2955
  async def getUnivPropCount(self, propname, maxsize=None):
2935
2956
  '''
2936
2957
  Return the number of universal property rows in the layer for the given prop.
@@ -2942,6 +2963,29 @@ class Layer(s_nexus.Pusher):
2942
2963
 
2943
2964
  return await self.layrslab.countByPref(abrv, db=self.byprop, maxsize=maxsize)
2944
2965
 
2966
+ async def getTagPropCount(self, form, tag, prop):
2967
+ '''
2968
+ Return the number of property rows in the layer for the given form/tag/prop.
2969
+ '''
2970
+ try:
2971
+ abrv = self.getTagPropAbrv(form, tag, prop)
2972
+ except s_exc.NoSuchAbrv:
2973
+ return 0
2974
+
2975
+ return await self.layrslab.countByPref(abrv, db=self.bytagprop)
2976
+
2977
+ def getTagPropValuCount(self, form, tag, prop, stortype, valu):
2978
+ try:
2979
+ abrv = self.getTagPropAbrv(form, tag, prop)
2980
+ except s_exc.NoSuchAbrv:
2981
+ return 0
2982
+
2983
+ count = 0
2984
+ for indx in self.getStorIndx(stortype, valu):
2985
+ count += self.layrslab.count(abrv + indx, db=self.bytagprop)
2986
+
2987
+ return count
2988
+
2945
2989
  async def liftByTag(self, tag, form=None, reverse=False):
2946
2990
 
2947
2991
  try:
@@ -4151,76 +4195,6 @@ class Layer(s_nexus.Pusher):
4151
4195
  yield buid, s_msgpack.un(byts)
4152
4196
  await asyncio.sleep(0)
4153
4197
 
4154
- async def splices(self, offs=None, size=None):
4155
- '''
4156
- This API is deprecated.
4157
-
4158
- Yield (offs, splice) tuples from the nodeedit log starting from the given offset.
4159
-
4160
- Nodeedits will be flattened into splices before being yielded.
4161
- '''
4162
- s_common.deprdate('Layer.splices() API', s_common._splicedepr)
4163
- if not self.logedits:
4164
- return
4165
-
4166
- if offs is None:
4167
- offs = (0, 0, 0)
4168
-
4169
- if size is not None:
4170
-
4171
- count = 0
4172
- async for offset, nodeedits, meta in self.iterNodeEditLog(offs[0]):
4173
- async for splice in self.makeSplices(offset, nodeedits, meta):
4174
-
4175
- if splice[0] < offs:
4176
- continue
4177
-
4178
- if count >= size:
4179
- return
4180
-
4181
- yield splice
4182
- count = count + 1
4183
- else:
4184
- async for offset, nodeedits, meta in self.iterNodeEditLog(offs[0]):
4185
- async for splice in self.makeSplices(offset, nodeedits, meta):
4186
-
4187
- if splice[0] < offs:
4188
- continue
4189
-
4190
- yield splice
4191
-
4192
- async def splicesBack(self, offs=None, size=None):
4193
-
4194
- s_common.deprdate('Layer.splicesBack() API', s_common._splicedepr)
4195
- if not self.logedits:
4196
- return
4197
-
4198
- if offs is None:
4199
- offs = (await self.getEditIndx(), 0, 0)
4200
-
4201
- if size is not None:
4202
-
4203
- count = 0
4204
- async for offset, nodeedits, meta in self.iterNodeEditLogBack(offs[0]):
4205
- async for splice in self.makeSplices(offset, nodeedits, meta, reverse=True):
4206
-
4207
- if splice[0] > offs:
4208
- continue
4209
-
4210
- if count >= size:
4211
- return
4212
-
4213
- yield splice
4214
- count += 1
4215
- else:
4216
- async for offset, nodeedits, meta in self.iterNodeEditLogBack(offs[0]):
4217
- async for splice in self.makeSplices(offset, nodeedits, meta, reverse=True):
4218
-
4219
- if splice[0] > offs:
4220
- continue
4221
-
4222
- yield splice
4223
-
4224
4198
  async def iterNodeEditLog(self, offs=0):
4225
4199
  '''
4226
4200
  Iterate the node edit log and yield (offs, edits, meta) tuples.
@@ -4312,117 +4286,6 @@ class Layer(s_nexus.Pusher):
4312
4286
  if count % 1000 == 0:
4313
4287
  yield (curoff, (None, None, EDIT_PROGRESS, (), ()))
4314
4288
 
4315
- async def makeSplices(self, offs, nodeedits, meta, reverse=False):
4316
- '''
4317
- Flatten a set of nodeedits into splices.
4318
- '''
4319
- if meta is None:
4320
- meta = {}
4321
-
4322
- user = meta.get('user')
4323
- time = meta.get('time')
4324
- prov = meta.get('prov')
4325
-
4326
- if reverse:
4327
- nodegenr = reversed(list(enumerate(nodeedits)))
4328
- else:
4329
- nodegenr = enumerate(nodeedits)
4330
-
4331
- for nodeoffs, (buid, form, edits) in nodegenr:
4332
-
4333
- formvalu = None
4334
-
4335
- if reverse:
4336
- editgenr = reversed(list(enumerate(edits)))
4337
- else:
4338
- editgenr = enumerate(edits)
4339
-
4340
- for editoffs, (edit, info, _) in editgenr:
4341
-
4342
- if edit in (EDIT_NODEDATA_SET, EDIT_NODEDATA_DEL, EDIT_EDGE_ADD, EDIT_EDGE_DEL):
4343
- continue
4344
-
4345
- spliceoffs = (offs, nodeoffs, editoffs)
4346
-
4347
- props = {
4348
- 'time': time,
4349
- 'user': user,
4350
- }
4351
-
4352
- if prov is not None:
4353
- props['prov'] = prov
4354
-
4355
- if edit == EDIT_NODE_ADD:
4356
- formvalu, stortype = info
4357
- props['ndef'] = (form, formvalu)
4358
-
4359
- yield (spliceoffs, ('node:add', props))
4360
- continue
4361
-
4362
- if edit == EDIT_NODE_DEL:
4363
- formvalu, stortype = info
4364
- props['ndef'] = (form, formvalu)
4365
-
4366
- yield (spliceoffs, ('node:del', props))
4367
- continue
4368
-
4369
- if formvalu is None:
4370
- formvalu = await self.getNodeValu(buid)
4371
-
4372
- props['ndef'] = (form, formvalu)
4373
-
4374
- if edit == EDIT_PROP_SET:
4375
- prop, valu, oldv, stortype = info
4376
- props['prop'] = prop
4377
- props['valu'] = valu
4378
- props['oldv'] = oldv
4379
-
4380
- yield (spliceoffs, ('prop:set', props))
4381
- continue
4382
-
4383
- if edit == EDIT_PROP_DEL:
4384
- prop, valu, stortype = info
4385
- props['prop'] = prop
4386
- props['valu'] = valu
4387
-
4388
- yield (spliceoffs, ('prop:del', props))
4389
- continue
4390
-
4391
- if edit == EDIT_TAG_SET:
4392
- tag, valu, oldv = info
4393
- props['tag'] = tag
4394
- props['valu'] = valu
4395
- props['oldv'] = oldv
4396
-
4397
- yield (spliceoffs, ('tag:add', props))
4398
- continue
4399
-
4400
- if edit == EDIT_TAG_DEL:
4401
- tag, valu = info
4402
- props['tag'] = tag
4403
- props['valu'] = valu
4404
-
4405
- yield (spliceoffs, ('tag:del', props))
4406
- continue
4407
-
4408
- if edit == EDIT_TAGPROP_SET:
4409
- tag, prop, valu, oldv, stortype = info
4410
- props['tag'] = tag
4411
- props['prop'] = prop
4412
- props['valu'] = valu
4413
- props['oldv'] = oldv
4414
-
4415
- yield (spliceoffs, ('tag:prop:set', props))
4416
- continue
4417
-
4418
- if edit == EDIT_TAGPROP_DEL:
4419
- tag, prop, valu, stortype = info
4420
- props['tag'] = tag
4421
- props['prop'] = prop
4422
- props['valu'] = valu
4423
-
4424
- yield (spliceoffs, ('tag:prop:del', props))
4425
-
4426
4289
  @contextlib.asynccontextmanager
4427
4290
  async def getNodeEditWindow(self):
4428
4291
  if not self.logedits:
synapse/lib/lmdbslab.py CHANGED
@@ -1196,6 +1196,17 @@ class Slab(s_base.Base):
1196
1196
  with self.xact.cursor(db=realdb) as curs:
1197
1197
  return curs.set_key_dup(lkey, lval)
1198
1198
 
1199
+ def count(self, lkey, db=None):
1200
+ realdb, dupsort = self.dbnames[db]
1201
+ with self.xact.cursor(db=realdb) as curs:
1202
+ if not curs.set_key(lkey):
1203
+ return 0
1204
+
1205
+ if not dupsort:
1206
+ return 1
1207
+
1208
+ return curs.count()
1209
+
1199
1210
  def prefexists(self, byts, db=None):
1200
1211
  '''
1201
1212
  Returns True if a prefix exists in the db.
synapse/lib/node.py CHANGED
@@ -613,17 +613,15 @@ class Node:
613
613
  * delete all the tags (bottom up)
614
614
  * fire onDelTag() handlers
615
615
  * delete tag properties from storage
616
- * log tag:del splices
617
616
 
618
617
  * delete all secondary properties
619
618
  * fire onDelProp handler
620
619
  * delete secondary property from storage
621
- * log prop:del splices
622
620
 
623
621
  * delete the primary property
624
622
  * fire onDel handlers for the node
625
623
  * delete primary property from storage
626
- * log node:del splices
624
+
627
625
  '''
628
626
 
629
627
  formname, formvalu = self.ndef