├── c4dep.main.replink ├── .dockerignore ├── project └── build.properties ├── micro ├── kui │ ├── requirements.txt │ ├── kube_top.py │ ├── favicon.svg │ ├── Dockerfile │ └── kube_util.py ├── sleep │ └── Dockerfile ├── metrics4kafka │ ├── main.py │ └── Dockerfile ├── metrics4docker │ └── Dockerfile ├── ws4cam │ └── Dockerfile ├── memresize │ ├── Dockerfile │ └── README.md ├── umon │ ├── Dockerfile │ └── main.py ├── s3client │ ├── Dockerfile │ └── main.py └── dig │ └── Dockerfile ├── tools ├── patch.jar └── greys.tar.gz ├── base_lib └── src │ └── main │ ├── scala │ └── ee │ │ └── cone │ │ ├── c4actor_xml │ │ ├── Mix.scala │ │ └── S3ListerImpl.scala │ │ ├── c4actor_s3_minio │ │ └── MinioS3Mix.scala │ │ ├── c4actor_branch │ │ ├── ActorBranchMix.scala │ │ └── BranchApi.scala │ │ ├── c4actor_repl_impl │ │ ├── GateReplMix.scala │ │ └── Repl.scala │ │ ├── c4gate │ │ ├── ManagementApi.scala │ │ ├── AddrForKeyApi.scala │ │ ├── TimeApi.scala │ │ ├── AuthOperations.scala │ │ ├── OrigKeyGenerator.scala │ │ ├── SignedReqUtil.scala │ │ ├── PublishMimeImpl.scala │ │ ├── EventLogApi.scala │ │ ├── MetricsApi.scala │ │ ├── DevConfigApp.scala │ │ ├── PublishApi.scala │ │ ├── HttpUtilApi.scala │ │ ├── AuthOperationsImpl.scala │ │ ├── SessionAttrApi.scala │ │ └── SignedReqUtilImpl.scala │ │ ├── c4actor_logback_impl │ │ └── GateLogbackMix.scala │ │ ├── c4actor │ │ ├── dep_impl │ │ │ └── DepImplMix.scala │ │ ├── HashGenApi.scala │ │ ├── PreHashingApi.scala │ │ ├── RangerApi.scala │ │ ├── ArchiveLEvent.scala │ │ ├── ScalingApi.scala │ │ ├── MortalApi.scala │ │ ├── AssembleName.scala │ │ ├── DefaultUpdateProcessor.scala │ │ ├── IdGenUtilApi.scala │ │ ├── AccessApi.scala │ │ ├── UpdateIfChangedImpl.scala │ │ ├── CompressorApi.scala │ │ ├── AbstractMetaAttr.scala │ │ ├── HttpClientImpl.scala │ │ ├── ConsumerApi.scala │ │ ├── UniversalNodeApi.scala │ │ ├── ScalingTest.scala │ │ ├── TestContextFactory.scala │ │ ├── ProtocolApi.scala │ │ ├── KeyFactoryImpl.scala │ │ ├── SnapshotCheckResetImpl.scala │ │ ├── BigDecimalImpl.scala │ │ ├── SnapshotListApi.scala │ │ ├── HashSearchApi.scala │ │ ├── DeadlockDetect.scala │ │ ├── PreHashingImpl.scala │ │ ├── DefaultModelApi.scala │ │ ├── ConditionApi.scala │ │ ├── UniversalNodeImpl.scala │ │ ├── CompressorImpl.scala │ │ ├── ElectorApi.scala │ │ ├── DebugRawWorld.scala │ │ ├── IdGenUtilImpl.scala │ │ ├── OrigMetaImpl.scala │ │ ├── SnapshotRemoteImpl.scala │ │ └── ComponentApi.scala │ │ ├── c4gate_devel │ │ ├── DevelApi.scala │ │ └── DevelMix.scala │ │ ├── c4ui │ │ ├── FrontTypes.scala │ │ ├── ListApi.scala │ │ ├── SortApi.scala │ │ ├── UIMix.scala │ │ ├── SortImpl.scala │ │ ├── ListImpl.scala │ │ └── UIApi.scala │ │ ├── c4vdom_impl │ │ ├── Util.scala │ │ ├── MapVDomValueImpl.scala │ │ ├── VDomI.scala │ │ ├── VDomSync.scala │ │ └── VDomDiff.scala │ │ ├── c4actor_s3 │ │ └── S3Proto.scala │ │ ├── c4assemble │ │ ├── AssembleMix.scala │ │ ├── package.scala │ │ ├── Debug.scala │ │ ├── SpreaderApi.scala │ │ ├── PlannerApi.scala │ │ └── ByPriorityImpl.scala │ │ ├── c4vdom_mix │ │ └── VDom.scala │ │ ├── c4actor_kafka_impl │ │ ├── KafkaMix.scala │ │ └── LZ4Compressor.scala │ │ └── c4proto │ │ ├── package.scala │ │ └── DataCategory.scala │ └── java │ └── ee │ └── cone │ ├── c4assemble │ ├── MultiForPart.java │ ├── Interner.java │ ├── RawToPrimaryKey.java │ ├── RIndexBuffer.java │ ├── HashCodeCache.java │ └── gen.pl │ └── c4actor_kafka_impl │ └── KafkaMessageSender.java ├── .travis.yml ├── extra_lib └── src │ └── main │ ├── scala │ └── ee │ │ └── cone │ │ ├── c4actor │ │ ├── QAdapterRegistryApp.scala │ │ ├── dep │ │ │ ├── DepFactoryApp.scala │ │ │ ├── DepAskFactoryApp.scala │ │ │ ├── AskByPKFactoryApp.scala │ │ │ ├── DepRequestFactoryApp.scala │ │ │ ├── DepResponseFactoryApp.scala │ │ │ └── request │ │ │ │ └── ContextIdRequest.scala │ │ ├── MurMur3PreHashingApp.scala │ │ ├── FilterPredicateApi.scala │ │ ├── QueueApiExtra.scala │ │ ├── hashsearch │ │ │ ├── base │ │ │ │ └── DepIndexNodeRegistry.scala │ │ │ ├── condition │ │ │ │ └── ConditionCheckWithCl.scala │ │ │ ├── rangers │ │ │ │ ├── RangerWithCl.scala │ │ │ │ └── HashSearchRangerRegistry.scala │ │ │ └── index │ │ │ │ ├── StaticHashSearchApi.scala │ │ │ │ └── dynamic │ │ │ │ └── IndexNodeProtocol.scala │ │ ├── package.scala │ │ ├── rdb │ │ │ ├── UniversalPropHandler.scala │ │ │ ├── ExternalActivator.scala │ │ │ ├── RDBApi.scala │ │ │ └── RDBExtensionApi.scala │ │ ├── rdb_impl │ │ │ └── ActorRDBMix.scala │ │ ├── time │ │ │ └── package.scala │ │ ├── LEventTransform.scala │ │ ├── dep_impl │ │ │ └── DepMix.scala │ │ └── ConsoleAssembleProfiler.scala │ │ ├── c4gate │ │ ├── deep_session │ │ │ ├── DeepFilterPredicateBuilderApp.scala │ │ │ ├── DeepSessionDataProtocol.scala │ │ │ ├── DeepSessionAttrApi.scala │ │ │ ├── DeepSessionAttrMix.scala │ │ │ └── DeepSessionDataAssemble.scala │ │ └── FilterPredicateApi.scala │ │ ├── c4actor_branch │ │ └── Compat.scala │ │ └── c4ui │ │ ├── dep │ │ ├── GateAskFactoryApi.scala │ │ └── GateAskMix.scala │ │ └── UIExtraMix.scala │ └── java │ └── ee │ └── cone │ └── c4actor │ ├── Java128HashInterface.java │ └── MurmurConstants.java ├── client ├── vsconf │ ├── package.json │ └── jsconfig.json └── src │ ├── extra │ ├── compat.txt │ └── canvas-mix.js │ ├── test │ └── ws-app.js │ └── main │ ├── react.ts │ ├── receiver.ts │ ├── sync-hooks.ts │ ├── location.ts │ └── frames.ts ├── base_examples └── src │ └── main │ └── scala │ └── ee │ └── cone │ ├── c4actor │ ├── Common.scala │ ├── DeadlockTest.scala │ └── BaseExamplesMix.scala │ ├── c4ui │ ├── UIExampleMix.scala │ └── ByLocationHashView.scala │ └── c4gate │ ├── TestTxTransform.scala │ ├── KafkaLatTestApp.scala │ ├── ConsumerExamplesMix.scala │ ├── HiRateTxApp.scala │ └── LongHungry.scala ├── base_server └── src │ └── main │ └── scala │ └── ee │ └── cone │ ├── c4gate_akka │ ├── AkkaMix.scala │ └── AkkaApi.scala │ └── c4gate_server │ ├── SnapshotApi.scala │ ├── SimpleMaker.scala │ ├── ServerApi.scala │ ├── PublisherImpl.scala │ └── LogPurging.scala ├── extra_examples └── src │ └── main │ └── scala │ └── ee │ └── cone │ ├── c4actor │ ├── Mix.scala │ ├── tests │ │ ├── SnapshotUtilTest.scala │ │ ├── TimeGenTest.scala │ │ ├── ScalametaTest.scala │ │ ├── GeneratorTest.scala │ │ └── SnapshotParser.scala │ ├── ActivateContext.scala │ ├── sandbox │ │ ├── SandboxProtocol.scala │ │ ├── SandboxBackEnd.scala │ │ └── SanboxLensTutuorial.scala │ └── Laboratory.scala │ ├── c4ui │ ├── AccessViewApi.scala │ ├── AccessViewImpl.scala │ └── FailOverTest.scala │ └── c4vdom │ ├── CanvasPathImpl.scala │ └── PathCommandApi.scala ├── dev_server ├── init.pl └── example.sh ├── .gitattributes ├── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── run_with_prefix.py ├── agent ├── cio.py ├── forward.py └── server.py ├── ceph.pl ├── generator └── src │ └── main │ └── scala │ └── ee │ └── cone │ └── c4generator │ ├── Utils.scala │ ├── ByPriority.scala │ └── ValInNonFinalGenerator.scala ├── c4util ├── cmd.py ├── servers.py ├── kube_reporter.py ├── s3sign.java ├── git.py ├── cio_preproc.py └── notify.py ├── sync_mem.pl ├── repos.pl ├── join_rules_q.pl ├── README.md ├── vault.py ├── assemble_log2html.pl ├── elector.js ├── c4dep.gate.json ├── run.pl ├── ci_up.py ├── gitlab-gen.py ├── ci_prep.py └── perl_script_relations.txt /c4dep.main.replink: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.9.3 2 | -------------------------------------------------------------------------------- /micro/kui/requirements.txt: -------------------------------------------------------------------------------- 1 | websockets==15.0.1 2 | boto3==1.38.34 3 | -------------------------------------------------------------------------------- /tools/patch.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conecenter/c4proto/HEAD/tools/patch.jar -------------------------------------------------------------------------------- /tools/greys.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/conecenter/c4proto/HEAD/tools/greys.tar.gz -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_xml/Mix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_xml 2 | 3 | trait S3ListerAppBase 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | scala: 3 | - 2.11.8 4 | jdk: 5 | - oraclejdk8 6 | script: 7 | - sbt clean test 8 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_s3_minio/MinioS3Mix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_s3_minio 2 | 3 | trait MinioS3AppBase -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_branch/ActorBranchMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_branch 2 | 3 | trait BranchAppBase 4 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_repl_impl/GateReplMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_repl_impl 2 | 3 | trait SSHDebugAppBase 4 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/QAdapterRegistryApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | @deprecated trait QAdapterRegistryApp -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/ManagementApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | case class LocalHttpConsumer(condition: String) 4 | -------------------------------------------------------------------------------- /client/vsconf/package.json: -------------------------------------------------------------------------------- 1 | {"dependencies":{"@types/react":"^18.3.12","@types/react-dom":"^18.3.1","react":"^18.3.1","react-dom":"^18.3.1"}} -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_logback_impl/GateLogbackMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_logback_impl 2 | 3 | trait BasicLoggingAppBase 4 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4actor/Common.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | object IgnoreTestContext { 4 | def apply(local: Context): Unit = () 5 | } -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/dep/DepFactoryApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep 2 | 3 | trait DepFactoryApp { 4 | def depFactory: DepFactory 5 | } 6 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/dep_impl/DepImplMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep_impl 2 | 3 | trait ByPKRequestHandlerCompAppBase 4 | trait DepAssembleCompAppBase -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/dep/DepAskFactoryApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep 2 | 3 | trait DepAskFactoryApp { 4 | def depAskFactory: DepAskFactory 5 | } 6 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/dep/AskByPKFactoryApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep 2 | 3 | trait AskByPKFactoryApp { 4 | def askByPKFactory: AskByPKFactory 5 | } 6 | -------------------------------------------------------------------------------- /base_lib/src/main/java/ee/cone/c4assemble/MultiForPart.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble; 2 | public interface MultiForPart { 3 | boolean isChanged(); 4 | scala.Product[] items(); 5 | } 6 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/AddrForKeyApi.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4gate 3 | 4 | import ee.cone.c4actor.Types.SrcId 5 | 6 | case class AddrForKey(srcId: SrcId, addr: String) 7 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/dep/DepRequestFactoryApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep 2 | 3 | trait DepRequestFactoryApp { 4 | def depRequestFactory: DepRequestFactory 5 | } 6 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/dep/DepResponseFactoryApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep 2 | 3 | trait DepResponseFactoryApp { 4 | def depResponseFactory: DepResponseFactory 5 | } 6 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate_devel/DevelApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate_devel 2 | 3 | import java.nio.file.Path 4 | 5 | trait FileConsumerDir { 6 | def resolve(p: String): Path 7 | } 8 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/HashGenApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | trait HashGen { 4 | def generate[Model](m: Model): String 5 | def generateLong[Model](m: Model): (Long, Long) 6 | } -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/MurMur3PreHashingApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | trait MurMur3PreHashingApp { 4 | def murMur3PreHashing: PreHashingMurMur3 = PreHashingMurMur3() 5 | } 6 | -------------------------------------------------------------------------------- /micro/sleep/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | USER c4 5 | ENTRYPOINT ["perl","-e","exec 'sleep','infinity';die"] -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4ui/FrontTypes.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | object FrontTypes { 4 | /** 5 | * Type for passing Em, will be rounded to 10^-3 6 | */ 7 | type Em = BigDecimal 8 | } 9 | -------------------------------------------------------------------------------- /base_server/src/main/scala/ee/cone/c4gate_akka/AkkaMix.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4gate_akka 3 | 4 | import ee.cone.c4gate_server.AbstractHttpGatewayApp 5 | 6 | trait AkkaGatewayAppBase extends AbstractHttpGatewayApp 7 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/PreHashingApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | trait PreHashing { 4 | def wrap[T](value: T): PreHashed[T] 5 | } 6 | 7 | trait PreHashed[T] { 8 | def value: T 9 | } 10 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/RangerApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | trait Ranger[By<:Product,Field] extends Product { 4 | def ranges: By => (Field => List[By], PartialFunction[Product,List[By]]) 5 | } 6 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/TimeApi.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4gate 3 | 4 | object Time { 5 | def hour: Long = 60L*minute 6 | def minute: Long = 60L*1000L 7 | def now: Long = System.currentTimeMillis 8 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4ui/ListApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | trait CSSClassName extends Product { 4 | def name: String 5 | } 6 | case object NoCSSClassName extends CSSClassName { def name: String = "" } 7 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ArchiveLEvent.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | 5 | case class ArchiveLEvent[+M <: Product](srcId: SrcId, className: String) extends LEvent[M] 6 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/FilterPredicateApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | trait FilterPredicateApi[Model <: Product] { 4 | def accesses: List[Access[_]] 5 | 6 | def condition: Condition[Model] 7 | } 8 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/QueueApiExtra.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4assemble.{AbstractAll, All} 4 | 5 | object WithAll { 6 | def apply[P<:Product](p: P): (AbstractAll,P) = All -> p 7 | } -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/Mix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | trait ActivateContextAppBase extends ComponentProviderApp { 4 | def activateContext: ActivateContext = resolveSingle(classOf[ActivateContext]) 5 | } 6 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ScalingApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | abstract class GeneralEnableSimpleScaling(val cl: Class[_]) 4 | 5 | class EnableSimpleScaling[T](cl: Class[T]) extends GeneralEnableSimpleScaling(cl) 6 | -------------------------------------------------------------------------------- /base_server/src/main/scala/ee/cone/c4gate_server/SnapshotApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate_server 2 | 3 | import ee.cone.c4actor.SnapshotInfo 4 | 5 | trait SnapshotRemover { 6 | def deleteIfExists(snapshot: SnapshotInfo): Boolean 7 | } 8 | 9 | -------------------------------------------------------------------------------- /client/src/extra/compat.txt: -------------------------------------------------------------------------------- 1 | 2 | /*to fix: 3 | busyFor in context sender 4 | original VDomSender returns obj 5 | 6 | 7 | return createSyncProviders({ ack, isRoot, branchKey, sender: inpSender, children: elementWeakCache(incoming) }) 8 | */ 9 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/hashsearch/base/DepIndexNodeRegistry.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.hashsearch.base 2 | 3 | trait DepIndexNodeRegistry { 4 | def get[By <: Product, Field](byName: String, fieldName: String): String 5 | } 6 | -------------------------------------------------------------------------------- /micro/metrics4kafka/main.py: -------------------------------------------------------------------------------- 1 | from subprocess import check_call 2 | from pathlib import Path 3 | 4 | cp = Path("/c4/kafka-clients-classpath").read_bytes().decode().strip() 5 | check_call(("java", "--source", "21", "--enable-preview", "-cp", cp, "/app/main.java")) -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4gate/deep_session/DeepFilterPredicateBuilderApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate.deep_session 2 | 3 | import ee.cone.c4gate.FilterPredicateBuilderApp 4 | 5 | trait DeepFilterPredicateBuilderApp extends FilterPredicateBuilderApp 6 | -------------------------------------------------------------------------------- /base_lib/src/main/java/ee/cone/c4assemble/Interner.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble; 2 | 3 | public class Interner { 4 | static boolean enabled = false; 5 | public static String intern(String s) { 6 | return enabled ? s.intern() : s; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /dev_server/init.pl: -------------------------------------------------------------------------------- 1 | 2 | use strict; 3 | 4 | sub sy{ print join(" ",@_),"\n"; system @_ and die $?; } 5 | my $exec = sub{ print join(" ",@_),"\n"; exec @_; die 'exec failed' }; 6 | 7 | sy("/replink.pl"); 8 | &$exec("perl","$ENV{C4DS_PROTO_DIR}/dev_server/serve.pl","init_dev"); 9 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/package.scala: -------------------------------------------------------------------------------- 1 | package ee.cone 2 | 3 | package object c4actor { 4 | // @deprecated type KafkaProducerApp = ee.cone.c4actor_kafka_impl.KafkaProducerApp 5 | // @deprecated type KafkaConsumerApp = ee.cone.c4actor_kafka_impl.KafkaConsumerApp 6 | 7 | } 8 | -------------------------------------------------------------------------------- /micro/metrics4docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | RUN perl install.pl apt curl ca-certificates tini python3 openssh-client 5 | USER c4 6 | ENTRYPOINT ["tini","--","python3","-u","/app/main.py"] -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/MortalApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4assemble.Assemble 5 | 6 | object LifeTypes { 7 | type Alive = SrcId 8 | } 9 | 10 | trait MortalFactory { 11 | def apply[P<:Product](p: Class[P]): Assemble 12 | } 13 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/rdb/UniversalPropHandler.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.rdb 2 | 3 | import ee.cone.c4actor.UniversalProp 4 | 5 | trait CustomFieldAdapter { 6 | def supportedCl: Class[_] 7 | def encode(value: Object): String 8 | def toUniversalProp(tag: Int, value: String): UniversalProp 9 | } -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/hashsearch/condition/ConditionCheckWithCl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.hashsearch.condition 2 | 3 | import ee.cone.c4actor.ConditionCheck 4 | 5 | abstract class ConditionCheckWithCl[By <: Product, Field](val byCl: Class[By],val fieldCl: Class[Field]) extends ConditionCheck[By, Field] 6 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/AssembleName.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | abstract class AssembleName(name: String, classes: Class[_]*) { 4 | private lazy val classStr: String = if (classes.isEmpty) "" else s"[${classes.map(_.getSimpleName).mkString(",")}]" 5 | lazy val getName: String = s"$name$classStr" 6 | } 7 | 8 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/AuthOperations.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4gate.AuthProtocol.N_SecureHash 4 | 5 | trait AuthOperations { 6 | def createHash(password: String, userHashOpt: Option[N_SecureHash]): N_SecureHash 7 | def verify(password: String, correctHash: N_SecureHash): Boolean 8 | } 9 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4vdom_impl/Util.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4vdom_impl 2 | 3 | import java.nio.charset.StandardCharsets.UTF_8 4 | 5 | object Never { 6 | def apply(): Nothing = throw new Exception("Never Here") 7 | } 8 | 9 | object UTF8String { 10 | def apply(data: Array[Byte]) = new String(data,UTF_8) 11 | } 12 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Declare files that will always have LF line endings on checkout. 5 | *.scala text eol=lf 6 | *.java text eol=lf 7 | *.pl text eol=lf 8 | *.js text eol=lf 9 | *.sbt text eol=lf 10 | *.git* text eol=lf 11 | *.json text eol=lf 12 | *.dockerfile text eol=lf -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/rdb_impl/ActorRDBMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.rdb_impl 2 | 3 | import ee.cone.c4actor.rdb.ExternalActivatorApp 4 | 5 | trait IndentedParserAppBase 6 | trait RDBSyncAppBase extends ExternalActivatorApp with IndentedParserApp 7 | trait ToExternalDBSyncAppBase extends RDBSyncApp 8 | trait FromExternalDBSyncAppBase extends RDBSyncApp -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_s3/S3Proto.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_s3 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4proto.{Id, protocol} 5 | 6 | @protocol object S3Proto { 7 | @Id(0x1010) case class E_S3FileRecord( 8 | //@Id(0x2605) srcId: SrcId, 9 | @Id(0x1011) filename: SrcId, 10 | @Id(0x1012) uploaded: Option[Long], 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/DefaultUpdateProcessor.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.QProtocol.N_Update 4 | 5 | import scala.collection.immutable 6 | import scala.collection.immutable.Seq 7 | 8 | class DefaultUpdateProcessor extends UpdateProcessor { 9 | def process(updates: Seq[N_Update], prevQueueSize: Int): Seq[N_Update] = updates 10 | } 11 | -------------------------------------------------------------------------------- /micro/ws4cam/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | RUN perl install.pl apt curl ca-certificates python3-venv tini lsof 5 | USER c4 6 | RUN python3 -m venv /c4/venv && /c4/venv/bin/pip install --no-cache-dir av pillow websockets 7 | ENTRYPOINT ["tini","--","/c4/venv/bin/python","-u","/app/ws4cam.py"] 8 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor_branch/Compat.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_branch 2 | 3 | import ee.cone.c4actor.Context 4 | 5 | trait ToAlienSender { 6 | def send(sessionKeys: Seq[String], evType: String, data: String): Context=>Context 7 | } 8 | 9 | // it does not work; todo replace consistent blocking with optimistic updates 10 | @deprecated trait BranchMessage extends Product 11 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4assemble/AssembleMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble 2 | 3 | import ee.cone.c4di.{c4, provide} 4 | 5 | trait AssembleAppBase 6 | 7 | @c4("AssembleApp") final class RIndexUtilProvider(arrayUtil: ArrayUtil)(inner: RIndexUtil = new RIndexUtilImpl(arrayUtil)()){ 8 | @provide def getRIndexUtil: Seq[RIndexUtil] = Seq(inner) 9 | //Seq(new RIndexUtilDebug(inner)) 10 | } 11 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/OrigKeyGenerator.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.IdGenUtil 4 | import ee.cone.c4proto._ 5 | 6 | trait KeyGenerator { 7 | def idGenUtil: IdGenUtil 8 | 9 | def genPK[P <: Product](model: P, adapter: ProtoAdapter[Product] with HasId): String = 10 | idGenUtil.srcIdFromSerialized(adapter.id,ToByteString(adapter.encode(model))) 11 | } 12 | -------------------------------------------------------------------------------- /micro/memresize/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | RUN perl install.pl apt curl ca-certificates python3 tini 5 | RUN perl install.pl curl https://dl.k8s.io/release/v1.33.1/bin/linux/amd64/kubectl && chmod +x /tools/kubectl 6 | USER c4 7 | ENV PATH=${PATH}:/tools 8 | ENTRYPOINT ["tini","--","python3","-u","/app/main.py"] 9 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/IdGenUtilApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import okio.ByteString 5 | 6 | trait IdGenUtil extends Product { 7 | def srcIdFromSrcIds(srcIdList: SrcId*): SrcId 8 | def srcIdFromStrings(stringList: String*): SrcId 9 | def srcIdFromSerialized(adapterId: Long, bytes: ByteString): SrcId 10 | def srcIdRandom(): SrcId 11 | } 12 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/tests/SnapshotUtilTest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.tests 2 | 3 | import ee.cone.c4actor.{RawSnapshot, SnapshotUtilImpl} 4 | 5 | object SnapshotUtilTest { 6 | def main(args: Array[String]): Unit = { 7 | val sn = "snapshots/0000000000009b70-ff5a4654-8a0f-377e-9616-d3d64cfa0131-gzip-a-u-u" 8 | println(SnapshotUtilImpl.hashFromName(RawSnapshot(sn))) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4vdom_mix/VDom.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4vdom_mix 2 | 3 | import ee.cone.c4vdom._ 4 | import ee.cone.c4vdom_impl._ 5 | 6 | @deprecated trait VDomApp { 7 | lazy val childPairFactory: ChildPairFactory = new ChildPairFactoryImpl(new VDomFactoryImpl(MapVDomValueImpl)) 8 | lazy val tagJsonUtils: TagJsonUtils = TagJsonUtilsImpl 9 | lazy val vDomResolver: VDomResolver = VDomResolverImpl 10 | } 11 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Status 2 | **READY/IN DEVELOPMENT/HOLD** 3 | 4 | ## Cross module movements 5 | YES | NO 6 | 7 | ## Description 8 | A few sentences describing the overall goals of the pull request's commits. 9 | 10 | ## Changes 11 | - Feature 1 12 | - Feature 2 13 | 14 | ## Impacted Areas in Application 15 | List general components of the application that this PR will affect: 16 | 17 | * Feature 1 18 | * Feature 2 19 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/SignedReqUtil.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.Types.LEvents 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4gate.HttpProtocol._ 6 | 7 | trait SignedReqUtil { 8 | def catchNonFatal: CatchNonFatal 9 | def signed(headers: List[N_Header]): Option[String] 10 | def respond(succeeded: List[(S_HttpRequest, List[N_Header])], failed: List[(S_HttpRequest, String)]): LEvents 11 | } 12 | -------------------------------------------------------------------------------- /base_lib/src/main/java/ee/cone/c4assemble/RawToPrimaryKey.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble; 2 | 3 | import scala.Product; 4 | 5 | public class RawToPrimaryKey { 6 | public static String get(Product p){ 7 | while(true) { 8 | if (p.productArity() == 0) return ""; 9 | Object k = p.productElement(0); 10 | if (k instanceof String) return (String) k; 11 | p = (Product) k; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /base_server/src/main/scala/ee/cone/c4gate_server/SimpleMaker.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate_server 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4assemble.Single 6 | import ee.cone.c4di.c4 7 | 8 | /* 9 | @c4("SimpleMakerApp") final class SimpleMakerExecutable(snapshotMaker: SnapshotMaker) extends Executable { 10 | def run(): Unit = { 11 | val rawSnapshot = snapshotMaker.make(???) 12 | } 13 | }*/ 14 | -------------------------------------------------------------------------------- /client/vsconf/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "jsx": "react-jsx", 5 | "moduleResolution":"bundler", 6 | "strict": true, 7 | "exactOptionalPropertyTypes": true, 8 | "noImplicitReturns": true, 9 | "noPropertyAccessFromIndexSignature": true, 10 | "noUncheckedIndexedAccess": true, 11 | "strictFunctionTypes": true, 12 | "noLib": true 13 | } 14 | } -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/rdb/ExternalActivator.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.rdb 2 | 3 | import ee.cone.c4di.c4 4 | 5 | 6 | /** 7 | * Component which defines if app has connection to external 8 | */ 9 | trait ExternalActivator 10 | 11 | trait ExternalActivatorAppBase 12 | 13 | @c4("ExternalActivatorApp") final class ExternalIsActive( 14 | activeMode: Option[ExternalActivator] 15 | ) { 16 | lazy val isActive: Boolean = activeMode.nonEmpty 17 | } 18 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_kafka_impl/KafkaMix.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4actor_kafka_impl 3 | 4 | import ee.cone.c4actor.LOBrokerApp 5 | 6 | trait KafkaConfigAppBase 7 | trait KafkaProducerAppBase extends KafkaConfigApp with LOBrokerApp 8 | trait KafkaConsumerAppBase extends KafkaConfigApp with LZ4DeCompressorApp with LOBrokerApp 9 | trait LZ4DeCompressorAppBase 10 | trait LZ4RawCompressorAppBase 11 | trait KafkaPurgerAppBase 12 | trait DisableDefaultKafkaConsumingAppBase 13 | -------------------------------------------------------------------------------- /base_server/src/main/scala/ee/cone/c4gate_akka/AkkaApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate_akka 2 | 3 | import scala.concurrent.{ExecutionContext, Future} 4 | import akka.stream.ActorMaterializer 5 | import akka.http.scaladsl.model.{HttpRequest,HttpResponse} 6 | 7 | trait AkkaMat { 8 | def get: Future[ActorMaterializer] 9 | } 10 | 11 | trait AkkaRequestHandler { 12 | def pathPrefix: String 13 | def handleAsync(req: HttpRequest)(implicit ec: ExecutionContext): Future[HttpResponse] 14 | } 15 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4ui/AccessViewApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor.{Access, Context} 4 | import ee.cone.c4vdom.{ChildPair, OfDiv} 5 | 6 | trait AccessViewRegistry { 7 | def view[P](access: Access[P]): Context=>ViewRes 8 | } 9 | 10 | abstract class GeneralAccessView(val valueClass: Class[_]) 11 | abstract class AccessView[P](valueClass: Class[P]) extends GeneralAccessView(valueClass) { 12 | def view(access: Access[P]): Context=>ViewRes 13 | } 14 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/AccessApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | //import ee.cone.c4actor.Types.SrcId 4 | 5 | 6 | trait Access[C] extends Product{ 7 | def updatingLens: Option[Lens[Context,C]] 8 | def initialValue: C 9 | def metaList: List[AbstractMetaAttr] 10 | def to[I](inner: ProdLens[C,I]): Access[I] 11 | def +(metaAttrs: AbstractMetaAttr*): Access[C] 12 | } 13 | 14 | trait RModelAccessFactory { 15 | def to[P <: Product](key: GetByPK[P], product: P): Access[P] 16 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/PublishMimeImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4di.c4 4 | 5 | @c4("PublishingCompApp") final class DefMimeTypesProvider extends PublishMimeTypesProvider { 6 | def get: List[(String, String)] = List( //not finished on gate-server side 7 | "html" -> "text/html; charset=UTF-8", 8 | "js" -> "application/javascript", 9 | "ico" -> "image/x-icon", 10 | "svg" -> "image/svg+xml", 11 | "zip" -> "application/zip", 12 | ) 13 | } 14 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4assemble/package.scala: -------------------------------------------------------------------------------- 1 | package ee.cone 2 | 3 | import scala.annotation.StaticAnnotation 4 | 5 | package object c4assemble { 6 | class assemble extends StaticAnnotation 7 | class c4assemble(apps: String*) extends StaticAnnotation 8 | class c4multiAssemble(apps: String*) extends StaticAnnotation 9 | class fieldAccess extends StaticAnnotation 10 | class ignore extends StaticAnnotation 11 | type MakeJoinKey = IndexUtil=>JoinKey 12 | type DOut = RIndexPair 13 | } 14 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/dep/request/ContextIdRequest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep.request 2 | 3 | import ee.cone.c4proto.{Id, protocol} 4 | 5 | trait ContextIdRequestProtocolAppBase 6 | 7 | @protocol("ContextIdRequestProtocolApp") object ContextIdRequestProtocol { 8 | @Id(0x0f31) case class N_ContextIdRequest() 9 | 10 | @Id(0x0f3a) case class N_UserIdRequest() 11 | 12 | @Id(0x0f5b) case class N_RoleIdRequest() 13 | 14 | @Id(0x0f5d) case class N_MockRoleRequest() 15 | } 16 | 17 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/UpdateIfChangedImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4assemble.ToPrimaryKey 4 | import ee.cone.c4di.c4 5 | 6 | @c4("RichDataCompApp") final class UpdateIfChangedImpl extends UpdateIfChanged { 7 | def updateSimple[T<:Product](getByPK: GetByPK[T]): Context=>Seq[T]=>Seq[LEvent[Product]] = local => { 8 | val was = getByPK.ofA(local) 9 | origSeq => LEvent.update(origSeq.filterNot(o=>was.get(ToPrimaryKey(o)).contains(o))) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | 4 | # sbt specific 5 | .cache 6 | .history 7 | .lib/ 8 | dist/* 9 | target/ 10 | lib_managed/ 11 | src_managed/ 12 | project/boot/ 13 | project/plugins/project/ 14 | 15 | # Scala-IDE specific 16 | .scala_dependencies 17 | .worksheet 18 | 19 | ### 20 | 21 | .idea 22 | tmp/ 23 | 24 | build 25 | node_modules 26 | db-* 27 | db4* 28 | db.* 29 | htdocs 30 | /logback.xml 31 | *.auth 32 | c4gen.* 33 | c4gen-* 34 | 35 | c4front 36 | .bloop 37 | 38 | *.out 39 | 40 | __pycache__ 41 | 42 | .bsp 43 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/CompressorApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import okio.BufferedSource 4 | 5 | sealed trait NamedCompressing { 6 | def name: String 7 | } 8 | 9 | trait DeCompressor extends NamedCompressing { 10 | def deCompress(compressed: BufferedSource): BufferedSource 11 | } 12 | 13 | trait RawCompressor extends NamedCompressing { 14 | def compress(data: Array[Byte]): Array[Byte] 15 | } 16 | 17 | trait StreamCompressorFactory { 18 | def create(): Option[RawCompressor] 19 | } 20 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/AbstractMetaAttr.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4proto.{Id, protocol} 4 | 5 | import scala.annotation.StaticAnnotation 6 | 7 | trait AbstractMetaAttr extends Product 8 | 9 | case class Meta(meta: AbstractMetaAttr*) extends StaticAnnotation 10 | 11 | case class MetaAttr(orig: Product) extends AbstractMetaAttr 12 | 13 | @protocol("ServerCompApp") object MetaAttrProtocol { 14 | @Id(0x00ad) case class D_TxTransformNameMeta( 15 | @Id(0x00ae) clName: String 16 | ) 17 | } -------------------------------------------------------------------------------- /client/src/test/ws-app.js: -------------------------------------------------------------------------------- 1 | 2 | import {CanvasUtil,ExchangeCanvasSetup,CanvasFactory} from "../extra/canvas" 3 | import {CanvasBaseMix,CanvasSimpleMix} from "../extra/canvas-mix" 4 | import {main} from "./ws-app.tsx" 5 | 6 | const log = v => console.log(v) 7 | const util = CanvasUtil() 8 | const exchangeMix = options => canvas => ExchangeCanvasSetup(canvas) 9 | const canvasMods = [CanvasBaseMix(log,util),CanvasSimpleMix(),exchangeMix] 10 | const canvasFactory = CanvasFactory(util, canvasMods) 11 | 12 | main({win: window, canvasFactory}) 13 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/HttpClientImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4di.c4 4 | 5 | import java.net.http.HttpClient 6 | import scala.concurrent.{Future, Promise} 7 | 8 | @c4("HttpClientApp") final class HttpClientProviderImpl(execution: Execution)( 9 | clientPromise: Promise[HttpClient] = Promise(), 10 | ) extends HttpClientProvider with Executable with Early { 11 | def run(): Unit = execution.success(clientPromise, HttpClient.newHttpClient) 12 | def get: Future[HttpClient] = clientPromise.future 13 | } 14 | -------------------------------------------------------------------------------- /micro/umon/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | RUN perl install.pl apt curl ca-certificates python3-venv tini 5 | USER c4 6 | RUN python3 -m venv /c4/venv && /c4/venv/bin/pip install --no-cache-dir playwright prometheus-client 7 | USER root 8 | RUN /c4/venv/bin/playwright install-deps && rm -rf /var/lib/apt/lists/* 9 | USER c4 10 | RUN /c4/venv/bin/playwright install chromium-headless-shell 11 | ENTRYPOINT ["tini","--","/c4/venv/bin/python","-u","/app/main.py"] 12 | -------------------------------------------------------------------------------- /micro/metrics4kafka/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | RUN perl install.pl apt curl ca-certificates tini python3 openjdk-21-jdk-headless 5 | RUN /install.pl curl https://github.com/coursier/launchers/raw/master/coursier && chmod +x /tools/coursier 6 | USER c4 7 | ENV PATH=${PATH}:/tools 8 | RUN coursier fetch --classpath org.apache.kafka:kafka-clients:3.7.1 > /c4/kafka-clients-classpath 9 | ENTRYPOINT ["tini","--","python3","-u","/app/main.py"] 10 | #COPY . /app 11 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ConsumerApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.NextOffset 4 | 5 | trait Consuming { 6 | def process[R](from: NextOffset, body: Consumer=>R): R 7 | // def process[R](from: List[(TxLogName,NextOffset)], body: Consumer=>R): R 8 | } 9 | trait Consumer { 10 | def poll(): List[RawEvent] 11 | def endOffset: NextOffset 12 | } 13 | 14 | trait QPurging { 15 | def process[R](txLogName: TxLogName, body: QPurger=>R): R 16 | } 17 | trait QPurger { 18 | def delete(beforeOffset: NextOffset): Unit 19 | } 20 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/UniversalNodeApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4proto._ 4 | 5 | trait UniversalNode { 6 | def props: List[UniversalProp] 7 | } 8 | 9 | trait UniversalProp { 10 | def tag: Int 11 | def value: Object 12 | def encodedValue: Array[Byte] 13 | def encodedSize: Int 14 | def encode(writer: ProtoWriter): Unit 15 | } 16 | 17 | trait UniversalNodeFactory { 18 | def node(props: List[UniversalProp]): UniversalNode 19 | def prop[T<:Object](tag: Int, value: T, adapter: ProtoAdapter[T]): UniversalProp 20 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/EventLogApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.AssembledContext 4 | import ee.cone.c4actor.Types.LEvents 5 | 6 | case class EventLogReadResult(events: Seq[String], next: Long) 7 | trait EventLogUtil { 8 | def create(): (String, LEvents) 9 | def read(world: AssembledContext, logKey: String, pos: Long): EventLogReadResult 10 | def write(world: AssembledContext, logKey: String, eventValue: String, snapshotOpt: Option[String]): LEvents 11 | def purgeAll(world: AssembledContext, logKey: String): LEvents 12 | } 13 | -------------------------------------------------------------------------------- /run_with_prefix.py: -------------------------------------------------------------------------------- 1 | 2 | import sys 3 | import subprocess 4 | import time 5 | 6 | def get_time_str(): 7 | m, s = divmod(int(time.monotonic()-started), 60) 8 | return f"{m}:{str(s).zfill(2)}" 9 | 10 | script, prefix, *args = sys.argv 11 | started = time.monotonic() 12 | get_prefix = get_time_str if prefix == "time" else lambda: prefix 13 | with subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) as proc: 14 | for line in proc.stdout: 15 | print(f"{get_prefix()} {line}",end="") 16 | proc.wait() 17 | sys.exit(proc.returncode) 18 | -------------------------------------------------------------------------------- /agent/cio.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 -u 2 | 3 | from subprocess import check_output 4 | from sys import argv, stderr 5 | 6 | def main(deploy_context, arg): 7 | kc = ("kubectl", "--context", deploy_context) 8 | pod = "svc/c4cio" 9 | res = check_output((*kc, "exec", pod, "--", "python3", "-u", "/ci_serve.py", f'[["call",{arg}]]')).decode().split() 10 | log_cmd = " ".join((*kc, "logs", pod, "-f", "--timestamps", "--tail", "1000")) 11 | grep = f" | grep {res[0]}" if len(res) == 1 else "" 12 | print(f"### to view logs:\n{log_cmd}{grep}", file=stderr) 13 | 14 | main(*argv[1:]) -------------------------------------------------------------------------------- /ceph.pl: -------------------------------------------------------------------------------- 1 | 2 | use strict; 3 | 4 | sub syf{ for(@_){ print "$_\n"; my $r = scalar `$_`; $? && die $?; return $r } } 5 | 6 | my $ceph_auth_path = $ENV{C4CEPH_AUTH}; 7 | if($ceph_auth_path eq "/tmp/ceph.auth"){ 8 | my $conf_dir = $ENV{C4S3_CONF_DIR}||die; 9 | my $content = join "&", map{"$$_[0]=$$_[1]"} 10 | (map{[$$_[0]=>syf("cat $conf_dir/$$_[1]")]} [url=>"address"],[id=>"key"],[pass=>"secret"]), 11 | [bucket=>$ENV{C4INBOX_TOPIC_PREFIX}||die]; 12 | open FF,">",$ceph_auth_path and print FF $content and close FF or die "put_text($!)($ceph_auth_path)"; 13 | } 14 | -------------------------------------------------------------------------------- /generator/src/main/scala/ee/cone/c4generator/Utils.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4generator 2 | 3 | import scala.meta.Tree 4 | 5 | object Utils { 6 | def parseError(s: Tree, parseContext: ParseContext, message: String = "") = 7 | throw GeneratorError(s"Can't parse structure ${s.toString()} ${if (message.nonEmpty) s"Reason: $message" else ""} at ${parseContext.path}:${s.pos.startLine + 1},${s.pos.startColumn + 1}") 8 | } 9 | 10 | final case class GeneratorError( 11 | private val message: String = "", 12 | //private val cause: Throwable = None.orNull 13 | ) 14 | extends Exception(message/*, cause*/) 15 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/MetricsApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.Context 4 | 5 | case class MetricLabel(name: String, value: String) 6 | 7 | case class Metric(name: String, labels: List[MetricLabel], value: Long) 8 | 9 | object Metric { 10 | def apply(name: String, value: Long): Metric = new Metric(name, Nil, value) 11 | } 12 | 13 | /** 14 | * Trait for defining metrics 15 | */ 16 | trait MetricsFactory { 17 | def measure(local: Context): List[Metric] 18 | } 19 | 20 | trait IndexMetricsProvider { 21 | def getClassNames(local: Context): Seq[String] 22 | } -------------------------------------------------------------------------------- /c4util/cmd.py: -------------------------------------------------------------------------------- 1 | 2 | from sys import argv 3 | from os import environ 4 | from json import dumps, loads 5 | from importlib import import_module 6 | from logging import basicConfig, DEBUG 7 | 8 | 9 | def get_cmd(f, *args): return ( 10 | "python3", "-u", "-c", "from c4util.cmd import run_cmd as f;f()", 11 | dumps([f.__module__, f.__name__,*(("env",*args[1:]) if args and args[0] is environ else ("",*args))]) 12 | ) 13 | 14 | 15 | def run_cmd(): 16 | mod, fun, pre_arg, *args = loads(argv[1]) 17 | basicConfig(level=DEBUG) 18 | getattr(import_module(mod), fun)(*([environ] if pre_arg=="env" else()),*args) 19 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4vdom_impl/MapVDomValueImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4vdom_impl 2 | 3 | import ee.cone.c4vdom.{MutableJsonBuilder, Resolvable, ResolvingVDomValue} 4 | 5 | case class MapVDomValueImpl(pairs: List[VPair]) extends MapVDomValue with ResolvingVDomValue { 6 | def appendJson(builder: MutableJsonBuilder) = { 7 | builder.startObject() 8 | pairs.foreach{ p => 9 | builder.just.append(p.jsonKey) 10 | p.value.appendJson(builder) 11 | } 12 | builder.end() 13 | } 14 | def resolve(name: String): Option[Resolvable] = 15 | pairs.find(_.jsonKey == name).map(_.value) 16 | } 17 | -------------------------------------------------------------------------------- /client/src/main/react.ts: -------------------------------------------------------------------------------- 1 | 2 | 3 | import {createElement,useState,useCallback,useEffect,useContext,createContext,useMemo,isValidElement} from "react" 4 | 5 | /* 6 | const useStateWrap = (initialState: S | (() => S)) => { 7 | const [state, setState] = useState(initialState) 8 | const setStateWrapper: React.Dispatch> = useCallback((...sArgs) => { 9 | console.trace("setState") 10 | setState(...sArgs) 11 | }, [setState]) 12 | return [state, setStateWrapper] 13 | } 14 | */ 15 | export {createElement,useState,useCallback,useEffect,useContext,createContext,useMemo,isValidElement} 16 | -------------------------------------------------------------------------------- /sync_mem.pl: -------------------------------------------------------------------------------- 1 | 2 | use strict; 3 | 4 | sub syf{ for(@_){ print "$_\n"; my $r = scalar `$_`; $? && die $?; return $r } } 5 | my $put_text = sub{ 6 | my($fn,$content)=@_; 7 | open FF,">:encoding(UTF-8)",$fn and print FF $content and close FF or die "put_text($!)($fn)"; 8 | }; 9 | 10 | my($dir)=@ARGV; 11 | my $content = join " ", sort map{ 12 | my $commit = syf("cd $dir && git --git-dir=$_ rev-parse --short HEAD")=~/(\S+)/ ? $1 : die; 13 | my $l_dir = m{^\./(|.*/)\.git$} ? $1 : die; 14 | "$l_dir:$commit"; 15 | } syf("cd $dir && find -name .git")=~/(\S+)/g; 16 | &$put_text("$dir/target/c4repo_commits",$content); 17 | -------------------------------------------------------------------------------- /extra_lib/src/main/java/ee/cone/c4actor/Java128HashInterface.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor; 2 | 3 | 4 | public interface Java128HashInterface { 5 | void reset(); 6 | 7 | String getStringHash(); 8 | 9 | long digest1(); 10 | 11 | long digest2(); 12 | 13 | void updateByte(byte a); 14 | 15 | void updateBoolean(boolean a); 16 | 17 | void updateInt(int a); 18 | 19 | void updateLong(long a); 20 | 21 | void updateString(String a); 22 | 23 | void updateLongs(long[] data, int length); 24 | 25 | void updateBytes(byte[] data, int length); 26 | 27 | void updateBytes(byte[] data); 28 | } 29 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4proto/package.scala: -------------------------------------------------------------------------------- 1 | package ee.cone 2 | 3 | import scala.annotation.StaticAnnotation 4 | 5 | package object c4proto { 6 | class protocol(apps: String*) extends StaticAnnotation 7 | 8 | /** 9 | * Defines that orig with this annotation can't have life given to it and can't be mortal 10 | */ 11 | class master(comment: String = "") extends StaticAnnotation 12 | 13 | type ProtoWriter = com.squareup.wire.ProtoWriter 14 | type ProtoReader = com.squareup.wire.ProtoReader 15 | type ProtoAdapter[T] = com.squareup.wire.ProtoAdapter[T] 16 | type GeneralProtoAdapter = Object // so any ProtoAdapter will extend Object 17 | } 18 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4assemble/Debug.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble 2 | 3 | import java.util.concurrent.atomic.{AtomicBoolean, AtomicLong} 4 | 5 | object DebugCounter { 6 | val values: IndexedSeq[AtomicLong] = (0 until 20).map(i=>new AtomicLong(0)) 7 | def add(pos: Int, d: Long): Unit = { 8 | val ignore = values(pos).addAndGet(d) 9 | } 10 | def report(): String = values.map(_.get()).mkString(" ") 11 | def reset(): Unit = for(v <- values) v.set(0) 12 | 13 | private val onV = (0 until 20).map(i=>new AtomicBoolean(false)) 14 | def on(pos: Int): Boolean = onV(pos).get 15 | def on(pos: Int, value: Boolean): Unit = onV(pos).set(value) 16 | } 17 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/rdb/RDBApi.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4actor.rdb 3 | 4 | import ee.cone.c4assemble.Assemble 5 | 6 | trait ExternalActive 7 | 8 | trait ExternalDBOption 9 | trait CommonDBOption extends ExternalDBOption{ 10 | def cl:Class[_] 11 | lazy val className: String = cl.getName 12 | } 13 | 14 | trait RDBOptionFactory { 15 | def fromDB[P<:Product](cl: Class[P]): ExternalDBOption 16 | def toDB[P<:Product](cl: Class[P], code: List[String]): ExternalDBOption 17 | } 18 | 19 | class ToDBOption(val cl:Class[_], val code: List[String], val assemble: Assemble) extends CommonDBOption 20 | class FromDBOption(val cl:Class[_]) extends CommonDBOption -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/hashsearch/rangers/RangerWithCl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.hashsearch.rangers 2 | 3 | import ee.cone.c4actor.Ranger 4 | 5 | object IndexType extends Enumeration { 6 | sealed trait IndexType extends Product 7 | case object Default extends IndexType 8 | case object Static extends IndexType 9 | case object Dynamic extends IndexType 10 | case object AutoStatic extends IndexType 11 | } 12 | 13 | import IndexType._ 14 | 15 | abstract class RangerWithCl[By <: Product, Field](val byCl: Class[By], val fieldCl: Class[Field]) extends Ranger[By, Field] { 16 | def indexType: IndexType = Default 17 | 18 | def prepareRequest: By => By 19 | } 20 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4gate/deep_session/DeepSessionDataProtocol.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate.deep_session 2 | 3 | import ee.cone.c4gate.SessionDataProtocol._ 4 | import ee.cone.c4proto.{Id, protocol} 5 | 6 | @protocol("SessionDataProtocolApp") object DeepSessionDataProtocol { 7 | 8 | @Id(0x0110) case class U_RawUserData( 9 | @Id(0x0111) srcId: String, 10 | @Id(0x0112) userId: String, 11 | @Id(0x0113) dataNode: Option[N_RawDataNode] // Always isDefined 12 | ) 13 | 14 | @Id(0x0117) case class U_RawRoleData( 15 | @Id(0x0118) srcId: String, 16 | @Id(0x0119) roleId: String, 17 | @Id(0x0120) dataNode: Option[N_RawDataNode] // Always isDefined 18 | ) 19 | 20 | } -------------------------------------------------------------------------------- /base_lib/src/main/java/ee/cone/c4assemble/RIndexBuffer.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble; 2 | 3 | public final class RIndexBuffer { 4 | public int end = 0; 5 | private final T[] values; 6 | public RIndexBuffer(T[] values) { 7 | this.values = values; 8 | } 9 | public void add(T value) { 10 | values[end++] = value; 11 | } 12 | public void add(T[] src, int srcStart, int sz) { 13 | if(sz==1) add(src[srcStart]); 14 | else { 15 | System.arraycopy(src, srcStart, values, end, sz); 16 | end += sz; 17 | } 18 | } 19 | public T[] result() { 20 | return java.util.Arrays.copyOf(values, end); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4ui/SortApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor.Context 4 | import ee.cone.c4vdom.Receiver 5 | import ee.cone.c4vdom.Types.VDomKey 6 | 7 | trait SortHandler extends Product { 8 | def handle(objKey: VDomKey, orderKeys: (VDomKey,VDomKey)): Context => Context 9 | } 10 | //trait SortTags { 11 | // def tBodyRoot(handler: SortHandler)(items: VDom[OfDiv]*): VDom[OfDiv] //todo OfTable 12 | // def handle(key: VDomKey, item: VDom[OfDiv]): VDom[OfDiv] 13 | //} 14 | 15 | trait SortReceiverFactory { 16 | def create(handler: SortHandler): Receiver[Context] 17 | } 18 | 19 | //trait SortReceiver extends Receiver[Context] { 20 | // def value: List[VDomKey] 21 | //} 22 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/ActivateContext.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.MetaAttrProtocol.D_TxTransformNameMeta 4 | import ee.cone.c4di.c4 5 | 6 | @c4("ActivateContextApp") final class ActivateContext( 7 | getTxTransform: GetByPK[TxTransform] 8 | ) { 9 | def apply(local: Context): Context = { 10 | val txTransforms = getTxTransform.ofA(local).values 11 | txTransforms.foldLeft(local)((oldLocal, transform) => 12 | transform.transform(TxTransformOrigMeta(transform.getClass.getName)(oldLocal))) 13 | } 14 | 15 | def main(args: Array[String]): Unit = { 16 | val list = List(1) 17 | println(list.nonEmpty, list.tail.isEmpty) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /extra_lib/src/main/java/ee/cone/c4actor/MurmurConstants.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor; 2 | 3 | public final class MurmurConstants { 4 | 5 | /** 6 | * Helps convert a byte into its unsigned value 7 | */ 8 | public static final int UNSIGNED_MASK = 0xff; 9 | 10 | /** 11 | * Helps convert integer to its unsigned value 12 | */ 13 | public static final long UINT_MASK = 0xFFFFFFFFl; 14 | 15 | /** 16 | * Helps convert long to its unsigned value 17 | */ 18 | public static final long LONG_MASK = 0xFFFFFFFFFFFFFFFFL; 19 | 20 | public static final long X64_128_C1 = 0x87c37b91114253d5L; 21 | 22 | public static final long X64_128_C2 = 0x4cf5ad432745937fL; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /agent/forward.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 -u 2 | 3 | from pathlib import Path 4 | from subprocess import Popen, DEVNULL, STDOUT 5 | from os import environ, kill 6 | from signal import SIGTERM 7 | from sys import stderr 8 | 9 | for p in [p for p in Path("/proc").iterdir() if p.name.isdigit()]: 10 | line = (p/"cmdline").read_bytes().split(b'\x00') 11 | if line[0] == b'kubectl' and b'port-forward' in line: kill(int(p.name), SIGTERM) 12 | kube_context, kind, pod_sel = Path("/tmp/c4pod").read_bytes().decode().split("~") 13 | cmd = ("kubectl","--context",kube_context,"port-forward","--address",environ["C4AGENT_IP"],f'{kind}/{pod_sel}',"4005") 14 | print(" ".join(cmd), file=stderr) 15 | Popen(cmd,stdout=DEVNULL,stderr=STDOUT) 16 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4proto/DataCategory.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4proto 2 | 3 | import scala.annotation.StaticAnnotation 4 | 5 | trait DataCategory extends Product 6 | 7 | case class Cat(category: DataCategory*) extends StaticAnnotation 8 | 9 | sealed trait DataTypeCategory extends DataCategory 10 | 11 | case object B_Cat extends DataTypeCategory 12 | case object C_Cat extends DataTypeCategory 13 | case object D_Cat extends DataTypeCategory 14 | case object E_Cat extends DataTypeCategory 15 | case object N_Cat extends DataTypeCategory 16 | case object S_Cat extends DataTypeCategory 17 | case object U_Cat extends DataTypeCategory 18 | case object V_Cat extends DataTypeCategory 19 | case object T_Cat extends DataTypeCategory -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ScalingTest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor.Types.{SrcId, TxEvents} 5 | import ee.cone.c4di.{c4, provide} 6 | 7 | @c4("ScalingTestApp") final class FailOverTestEnable 8 | extends EnableSimpleScaling(classOf[FailOverTestTx]) 9 | 10 | @c4("ScalingTestApp") final class FailOverTestProvider { 11 | @provide def toTx: Seq[SingleTxTr] = Seq(FailOverTestTx("FailOverTest-0"), FailOverTestTx("FailOverTest-1")) 12 | } 13 | 14 | case class FailOverTestTx(srcId: SrcId) extends SingleTxTr with LazyLogging { 15 | def transform(local: Context): TxEvents = { 16 | logger.info(s"Tx up $srcId") 17 | Nil 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/TestContextFactory.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4di.c4 4 | import ee.cone.c4proto.ToByteString 5 | import ee.cone.c4actor.QProtocol._ 6 | 7 | @c4("TestVMRichDataCompApp") final class ContextFactoryImpl( 8 | reducer: RichRawWorldReducer, 9 | toUpdate: ToUpdate, 10 | updateMapUtil: UpdateMapUtil, 11 | ) extends ContextFactory { 12 | def updated(updates: List[N_Update]): Context = { 13 | val (bytes, headers) = toUpdate.toBytes(updates.map(updateMapUtil.insert)) 14 | val firstUpdate = SimpleRawEvent("0" * OffsetHexSize(), ToByteString(bytes), headers) 15 | val world = reducer.createContext(Option(firstUpdate)) 16 | new Context(world.assembled, Map.empty) 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /dev_server/example.sh: -------------------------------------------------------------------------------- 1 | docker stop c4devel 2 | docker rm c4devel 3 | export C4DS_BUILD_DIR=/c4repo/c4proto 4 | export C4REPO_MAIN_CONF=/c4repo/c4proto/c4dep.main.replink 5 | export C4DEV_SERVER_MAIN=test-todo 6 | docker build -t c4devel --build-arg C4UID=$(id -u) . || exit 1 7 | export C4DEV_SERVER_IP="${C4DEV_SERVER_IP:-127.0.0.10}" 8 | docker run -d --rm --name c4devel \ 9 | -v $PWD/..:/c4repo/c4proto \ 10 | -v /dev/log:/dev/log \ 11 | -p $C4DEV_SERVER_IP:5173:5173 \ 12 | -p $C4DEV_SERVER_IP:80:1080 \ 13 | -e C4DS_PROTO_DIR=/c4repo/c4proto \ 14 | -e C4DS_ELECTOR_DIR=/c4repo/c4proto \ 15 | -e C4DS_BUILD_DIR=${C4DS_BUILD_DIR} \ 16 | -e C4REPO_MAIN_CONF=${C4REPO_MAIN_CONF} \ 17 | -e C4DEV_SERVER_MAIN=${C4DEV_SERVER_MAIN} \ 18 | -e C4MERGE_LOGS=1 \ 19 | c4devel || exit 1 -------------------------------------------------------------------------------- /base_lib/src/main/java/ee/cone/c4assemble/HashCodeCache.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble; 2 | 3 | import scala.Product; 4 | 5 | public class HashCodeCache { 6 | private final Product[] cacheItems; 7 | private final int[] cacheHashes; 8 | public HashCodeCache(int size){ 9 | cacheItems = new Product[size]; 10 | cacheHashes = new int[size]; 11 | } 12 | public int get(Product item){ 13 | if(cacheItems.length == 0) return item.hashCode(); 14 | final int pos = Math.floorMod(System.identityHashCode(item), cacheItems.length); 15 | if(cacheItems[pos] == item) return cacheHashes[pos]; 16 | int hash = item.hashCode(); 17 | cacheItems[pos] = item; 18 | cacheHashes[pos] = hash; 19 | return hash; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4assemble/SpreaderApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble 2 | 3 | trait LongGetter[S] { 4 | def get(src: S): Long 5 | } 6 | 7 | trait FlattenHandler[S,F,T] { 8 | def get(src: S): Array[F] 9 | def create(size: Int): Array[T] 10 | } 11 | 12 | trait SpreadHandler[N] { 13 | def toPos(it: N): Int 14 | def createPart(sz: Int): Array[N] 15 | def createRoot(sz: Int): Array[Array[N]] 16 | } 17 | 18 | trait ArrayUtil { 19 | def spread[N](src: Array[N], itemCount: Int, partCount: Int, handler: SpreadHandler[N]): Array[Array[N]] 20 | def flatten[S,F,T](srcs: Array[S], handler: FlattenHandler[S,F,T]): Array[T] 21 | def sum[S](src: Array[S], handler: LongGetter[S]): Long 22 | def max[S](src: Array[S], handler: LongGetter[S], start: Long): Long 23 | } 24 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4gate/deep_session/DeepSessionAttrApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate.deep_session 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4actor.{Access, Context, AbstractMetaAttr, TransientLens} 5 | import ee.cone.c4gate.{SessionAttr, SessionAttrAccessFactory} 6 | 7 | trait DeepSessionAttrAccessFactory extends SessionAttrAccessFactory{ 8 | def toUser[P <: Product](attr: SessionAttr[P]): Context => Access[P] 9 | 10 | def toRole[P <: Product](attr: SessionAttr[P]): Context => Access[P] 11 | } 12 | 13 | case object CurrentUserIdKey extends TransientLens[SrcId]("") 14 | 15 | case object CurrentRoleIdKey extends TransientLens[SrcId]("") 16 | 17 | case object UserLevelAttr extends AbstractMetaAttr 18 | 19 | case object RoleLevelAttr extends AbstractMetaAttr -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4gate/FilterPredicateApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4actor.{FilterPredicateApi, _} 5 | 6 | trait FilterPredicateBuilder { 7 | def create[Model<:Product]: Context => FilterPredicate[Model] 8 | 9 | def createWithPK[Model <: Product](filterPK: SrcId): Context => FilterPredicate[Model] 10 | } 11 | 12 | trait FilterPredicate[Model<:Product] extends FilterPredicateApi[Model] { 13 | 14 | def addAccess[By<:Product,Field](filterAccess: Access[By], lens: ProdGetter[Model,Field])(implicit c: ConditionCheck[By,Field]): FilterPredicate[Model] 15 | 16 | def add[By<:Product,Field](filterKey: SessionAttr[By], lens: ProdGetter[Model,Field])(implicit c: ConditionCheck[By,Field]): FilterPredicate[Model] 17 | } 18 | -------------------------------------------------------------------------------- /repos.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | 4 | sub syl{ for(@_){ print "$_\n"; my @r = `$_`; $? && die $?; return @r } } 5 | 6 | print syl("ssh-add"); 7 | my @dirs = map{ /^(.+).git\s*$/ ? "$1" : die } syl("find -iname .git"); 8 | for my $dir(@dirs){ 9 | print "####################################### $dir\n"; 10 | my $git = "cd $dir && git "; 11 | print syl("$git status"); 12 | my @set_msg = map{ 13 | m{^(origin)\s+https://github\.com/(\w+/\w+\.git)\s+\(push\)\s*$} ? do{ 14 | my($nm,$ln) = ($1,$2); 15 | "COPY/RUN: ($git remote set-url --push $nm git\@github.com:$ln)\n"; 16 | } : (); 17 | } syl("$git remote -v"); 18 | if(@set_msg){ print @set_msg } else {print `$git push origin --all --dry-run`} 19 | } 20 | 21 | #### CALL: ssh-agent c4proto/repos.pl -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/hashsearch/index/StaticHashSearchApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.hashsearch.index 2 | 3 | import ee.cone.c4actor.HashSearch.Request 4 | import ee.cone.c4actor.{Condition, ProdLens, ProdLensStrict, Ranger} 5 | import ee.cone.c4assemble.Assemble 6 | 7 | object StaticHashSearchApi { 8 | 9 | trait StaticFactory { 10 | def index[Model <: Product](model: Class[Model]): StaticIndexBuilder[Model] 11 | 12 | def request[Model <: Product](condition: Condition[Model]): Request[Model] 13 | } 14 | 15 | trait StaticIndexBuilder[Model <: Product] { 16 | def add[By <: Product, Field](lens: ProdLensStrict[Model, Field], by: By)( 17 | implicit ranger: Ranger[By, Field] 18 | ): StaticIndexBuilder[Model] 19 | 20 | def assemble: List[Assemble] 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/tests/TimeGenTest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.tests 2 | 3 | import ee.cone.c4actor.QProtocol.S_Firstborn 4 | import ee.cone.c4actor.{AssembledContext, TxTransform} 5 | import ee.cone.c4actor.Types.SrcId 6 | import ee.cone.c4actor.time._ 7 | import ee.cone.c4assemble.Types.{Each, Values} 8 | import ee.cone.c4assemble.c4assemble 9 | import ee.cone.c4di.c4 10 | 11 | @c4time(0x1337) case object TestTestTime extends CurrentTime(10L) 12 | 13 | @c4assemble class TestTimeAssembleBase { 14 | def test( 15 | srcId: SrcId, 16 | fb: Each[S_Firstborn], 17 | @time(TestTestTime) time: Each[T_Time] 18 | ): Values[(SrcId, TxTransform)] = Nil 19 | } 20 | 21 | @c4 final class TestTime(timeGetters: TimeGetters) { 22 | val test: AssembledContext => Option[T_Time] = timeGetters(TestTestTime).ofA 23 | } -------------------------------------------------------------------------------- /micro/s3client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | RUN perl install.pl apt curl ca-certificates python3-venv tini netcat-openbsd 5 | RUN /install.pl curl https://dl.min.io/client/mc/release/linux-amd64/mc && chmod +x /tools/mc 6 | RUN /install.pl curl https://download.bell-sw.com/java/21.0.4+9/bellsoft-jdk21.0.4+9-linux-amd64.tar.gz 7 | RUN /install.pl curl https://github.com/coursier/launchers/raw/master/coursier && chmod +x /tools/coursier 8 | USER c4 9 | ENV PATH=${PATH}:/tools:/tools/jdk/bin 10 | RUN coursier fetch --classpath org.apache.kafka:kafka-clients:3.7.1 > /c4/kafka-clients-classpath 11 | RUN python3 -m venv /c4/venv && /c4/venv/bin/pip install --no-cache-dir boto3==1.38.34 12 | ENTRYPOINT ["tini","--","python3","-u","/app/main.py","serve"] 13 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ProtocolApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4di.TypeKey 4 | import ee.cone.c4proto._ 5 | 6 | import scala.collection.immutable.Map 7 | 8 | abstract class GeneralDefaultArgument { 9 | def value: Any 10 | } 11 | abstract class DefaultArgument[Value](val value: Value) extends GeneralDefaultArgument 12 | abstract class ArgAdapterFactory(val key: TypeKey, val wrap: (()=>ProtoAdapter[Any])=>ArgAdapter[_]) 13 | abstract class LazyArgAdapterFactory(val key: TypeKey, val wrap: (()=>ProtoAdapter[Any])=>ArgAdapter[_]) 14 | 15 | object ArgTypes { 16 | type LazyOption[T] = Option[T] 17 | type LazyList[T] = List[T] 18 | } 19 | 20 | trait QAdapterRegistry extends Product { 21 | def byName: Map[String, ProtoAdapter[Product] with HasId] 22 | def byId: Map[Long, ProtoAdapter[Product] with HasId] 23 | } -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4ui/AccessViewImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4assemble.Single 5 | import ee.cone.c4di.c4 6 | import ee.cone.c4vdom.{ChildPair, OfDiv} 7 | 8 | @c4("AccessViewApp") final class InnerAccessViewRegistry(accessViews: List[GeneralAccessView])( 9 | val values: Map[String,GeneralAccessView] = CheckedMap(accessViews.map(v => v.valueClass.getName -> v)) 10 | ) 11 | 12 | @c4("AccessViewApp") final class AccessViewRegistryImpl( 13 | inner: DeferredSeq[InnerAccessViewRegistry] 14 | ) extends AccessViewRegistry { 15 | def view[P](access: Access[P]): Context=>ViewRes = local => { 16 | val general: GeneralAccessView = 17 | Single(inner.value).values(access.initialValue.getClass.getName) 18 | general.asInstanceOf[AccessView[P]].view(access)(local) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4assemble/PlannerApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble 2 | 3 | import ee.cone.c4assemble.PlannerTypes.TaskPos 4 | 5 | case class PlanTaskConf(users: Seq[TaskPos]) 6 | 7 | object PlannerTypes { 8 | type Tagged[U] = { type Tag = U } 9 | sealed trait TaskPosTag 10 | type TaskPos = Int with Tagged[TaskPosTag] 11 | } 12 | 13 | trait PlannerConf 14 | trait PlannerFactory { 15 | def createConf(exprConfByPos: Seq[PlanTaskConf]): PlannerConf 16 | def createMutablePlanner(conf: PlannerConf): MutablePlanner 17 | } 18 | 19 | trait MutablePlanner { 20 | def setTodo(exprPos: TaskPos, value: Boolean): Unit 21 | def setStarted(exprPos: TaskPos, value: Boolean): Unit 22 | def suggestedNonEmpty: Boolean 23 | def suggestedHead: TaskPos 24 | def planCount: Int 25 | def getStarted: Seq[TaskPos] 26 | def reportStarted(): Unit 27 | } 28 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4vdom_impl/VDomI.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4vdom_impl 2 | 3 | import ee.cone.c4vdom.Types.VDomKey 4 | import ee.cone.c4vdom._ 5 | 6 | trait JsonToString { 7 | def apply(value: VDomValue): String 8 | } 9 | 10 | trait WasNoVDomValue extends VDomValue 11 | 12 | trait VPair { 13 | def jsonKey: String 14 | def sameKey(other: VPair): Boolean 15 | def value: VDomValue 16 | def withValue(value: VDomValue): VPair 17 | } 18 | 19 | trait MapVDomValue extends VDomValue { 20 | def pairs: List[VPair] 21 | } 22 | 23 | trait Diff { 24 | def diff(prevValue: VDomValue, currValue: VDomValue): Option[MapVDomValue] 25 | } 26 | 27 | trait DuplicateKeysException extends Exception 28 | trait FixDuplicateKeys { 29 | def fix(ex: DuplicateKeysException, value: VDomValue): VDomValue 30 | } 31 | 32 | trait SeedVDomValue extends VDomValue { 33 | def seed: Product 34 | } -------------------------------------------------------------------------------- /join_rules_q.pl: -------------------------------------------------------------------------------- 1 | use strict; 2 | 3 | my @rules = grep{@$_}map{ 4 | [map{[/JK\((.+?)\)/g]} /^(.+)==>(.+)$/ ? ($1,$2) : ()]; 5 | } `cat /tmp/c4rules.out`; 6 | 7 | my ($q_in,$q_out) = @ARGV; 8 | 9 | if(!$q_out){ 10 | my %dep = ($q_in=>[]); 11 | for(@rules){ 12 | my ($ins,$outs)=@$_; 13 | for my $in(@$ins){ 14 | push @{$dep{$in}||next}, @$outs; 15 | $dep{$_}||=[] for @$outs; 16 | } 17 | } 18 | print map{"$_\n"} sort keys %dep; 19 | } else { 20 | my %dep; 21 | for(@rules){ 22 | my ($ins,$outs)=@$_; 23 | for my $in(@$ins){ 24 | push @{$dep{$in}||=[]}, @$outs; 25 | } 26 | } 27 | 28 | my $f; $f = sub{ 29 | $_[0] eq $q_out and return ($_[0]); 30 | for(@{$dep{$_[0]}||return}){ 31 | my @r=&$f($_); 32 | @r and return ($_[0],@r); 33 | } 34 | }; 35 | print map{my $n=scalar @{$dep{$_}||[]};"$_ $n\n"} &$f($q_in); 36 | } -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4ui/dep/GateAskFactoryApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui.dep 2 | 3 | import ee.cone.c4actor.Access 4 | import ee.cone.c4actor.Types.SrcId 5 | import ee.cone.c4actor.dep.{AskByPK, Dep} 6 | import ee.cone.c4actor.time.{CurrentTime, T_Time} 7 | import ee.cone.c4gate.SessionAttr 8 | 9 | trait SessionAttrAskFactory { 10 | def askSessionAttr[P <: Product](attr: SessionAttr[P]): Dep[Access[P]] 11 | def askSessionAttrWithPK[P <: Product](attr: SessionAttr[P]): String => Dep[Access[P]] 12 | def askSessionAttrWithDefault[P <: Product](attr: SessionAttr[P], default: SrcId => P): Dep[Access[P]] 13 | } 14 | 15 | /** 16 | * Needs to be @provide if used 17 | */ 18 | trait CurrentTimeRequestFactory { 19 | def ask: Dep[Long] 20 | def byPkAsk: AskByPK[_ <: T_Time] 21 | } 22 | 23 | trait CurrentTimeAskFactory { 24 | def askCurrentTime(time: CurrentTime): CurrentTimeRequestFactory 25 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/KeyFactoryImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.{ClName, SrcId} 4 | import ee.cone.c4assemble.Types.{Index, Values} 5 | import ee.cone.c4assemble.{AssembledKey, Getter, IndexUtil, Single, Types} 6 | import ee.cone.c4di.Types.ComponentFactory 7 | import ee.cone.c4di.{c4, provide} 8 | 9 | @c4("RichDataCompApp") final class SwitchOrigKeyFactoryHolder(proposition: Option[OrigKeyFactoryProposition], byPKKeyFactory: KeyFactory) 10 | extends OrigKeyFactoryFinalHolder(proposition.fold(byPKKeyFactory)(_.value)) 11 | 12 | @c4("RichDataCompApp") final case class DefaultKeyFactory(composes: IndexUtil)( 13 | srcIdAlias: String = "SrcId", 14 | srcIdClass: ClName = classOf[SrcId].getName 15 | ) extends KeyFactory { 16 | def rawKey(className: String): AssembledKey = 17 | composes.joinKey(was = false, srcIdAlias, srcIdClass, className) 18 | } 19 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/sandbox/SandboxProtocol.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.sandbox 2 | 3 | import ee.cone.c4actor.sandbox.OtherProtocol.{D_Other, D_Other2} 4 | import ee.cone.c4proto.{Id, protocol} 5 | 6 | /* 7 | This file can be edited for learning purposes, feel free to experiment here 8 | */ 9 | 10 | trait SandboxProtocolsAppBase 11 | 12 | 13 | @protocol("SandboxProtocolsApp") object SandboxProtocol { 14 | 15 | @Id(0x0230) case class D_Sandbox( 16 | @Id(0x0231) srcId: String, 17 | @Id(0x0232) value: Int, 18 | @Id(0x0233) otherOrig: Option[D_Other], 19 | @Id(0x0234) list: List[D_Other2] 20 | ) 21 | 22 | } 23 | 24 | @protocol("SandboxProtocolsApp") object OtherProtocol { 25 | 26 | @Id(0x0235) case class D_Other( 27 | @Id(0x0236) srcId: String 28 | ) 29 | 30 | @Id(0x0237) case class D_Other2( 31 | @Id(0x0238) srcId: String 32 | ) 33 | 34 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/DevConfigApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.ListConfig 4 | import ee.cone.c4di.c4 5 | 6 | import java.nio.file.{Files, Path, Paths} 7 | import scala.jdk.CollectionConverters.ListHasAsScala 8 | 9 | object FileConfigFactory { 10 | def create(paths: List[Path]): Map[String, List[String]] = (for { 11 | path <- paths if Files.exists(path) 12 | l <- Files.readAllLines(path).asScala 13 | p <- l.indexOf("=") match { case -1 => Nil case pos => Seq(l.substring(0,pos) -> l.substring(pos+1)) } 14 | } yield p).groupMap(_._1)(_._2) 15 | } 16 | 17 | @c4("DevConfigApp") final class DevConfig(inner: ListConfig)( 18 | fileEnvMap: Map[String, List[String]] = FileConfigFactory.create(inner.get("C4DEV_ENV").map(Paths.get(_))) 19 | ) extends ListConfig { 20 | def get(key: String): List[String] = fileEnvMap.getOrElse(key,Nil) ::: inner.get(key) 21 | } 22 | -------------------------------------------------------------------------------- /micro/kui/kube_top.py: -------------------------------------------------------------------------------- 1 | from subprocess import check_output 2 | from json import loads 3 | from time import time, sleep 4 | from os import environ 5 | from functools import partial 6 | from itertools import groupby 7 | 8 | def refresher(mut_states, kcp, context, url, key): 9 | kube_context = context["name"] 10 | loaded = 0 11 | while True: 12 | need_reload = (loaded or 0) < mut_states.get(("expired", kube_context), 0) 13 | if need_reload: 14 | items = loads(check_output((*kcp, kube_context, "get", "--raw", url), timeout=5))["items"] 15 | mut_states[(key, kube_context)] = items 16 | loaded = time() 17 | sleep(1) 18 | 19 | def init_kube_top(mut_metrics, contexts, kcp): 20 | return [ 21 | partial(refresher, mut_metrics, kcp, c, f"/apis/metrics.k8s.io/v1beta1/namespaces/{c["ns"]}/pods", "pod_metrics") 22 | for c in contexts 23 | ] 24 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/SnapshotCheckResetImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4assemble.Single 4 | import ee.cone.c4di.c4 5 | 6 | @c4("ServerCompApp") final class SnapshotCheckResetImpl( 7 | s3: S3Manager, currentTxLogName: CurrentTxLogName, execution: Execution, snapshotSaver: SnapshotSaver, 8 | rawQSenderExecutable: RawQSenderExecutable, getRawQSender: DeferredSeq[RawQSender], 9 | ) extends SnapshotCheckReset { 10 | private val resetPath = "snapshots/.reset" 11 | def run(): Unit = if(execution.aWait(s3.get(s3.join(currentTxLogName, resetPath))(_)).nonEmpty){ 12 | rawQSenderExecutable.run() 13 | val offset = Single(getRawQSender.value).send(new QRecord(Array.empty, Nil)) 14 | val res = snapshotSaver.save(offset, Array.empty, Nil) 15 | if(!execution.aWait(s3.delete(s3.join(currentTxLogName, resetPath))(_))) throw new Exception(s"no $resetPath") 16 | } 17 | } 18 | // -------------------------------------------------------------------------------- /client/src/extra/canvas-mix.js: -------------------------------------------------------------------------------- 1 | 2 | import * as Canvas from "./canvas" 3 | 4 | 5 | export function CanvasBaseMix(log,util){ 6 | return options => canvas => [ 7 | Canvas.BaseCanvasSetup(log,util,canvas), 8 | Canvas.ComplexFillCanvasSetup(util,canvas), 9 | Canvas.InteractiveCanvasSetup(canvas), 10 | options.singleTile ? 11 | Canvas.SingleTileCanvasSetup(canvas) : 12 | Canvas.TiledCanvasSetup(canvas), 13 | options.disableDragAndZoom ? 14 | Canvas.ScrollViewPositionCanvasSetup(canvas) : 15 | Canvas.DragViewPositionCanvasSetup(log,canvas), 16 | Canvas.ResizeCanvasSetup(canvas), 17 | Canvas.MouseCanvasSetup(log,canvas) 18 | ] 19 | } 20 | 21 | export function CanvasSimpleMix(){ 22 | return options => canvas => [ 23 | Canvas.NoOverlayCanvasSetup(canvas) 24 | ] 25 | } 26 | 27 | // \.\w+\s*=[^=] 28 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/time/package.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4actor.time.ProtoCurrentTimeConfig.T_Time 5 | 6 | import scala.annotation.StaticAnnotation 7 | 8 | package object time { 9 | 10 | class c4time(id: Long, appTrait: String*) extends StaticAnnotation 11 | 12 | class time(time: CurrentTime) extends StaticAnnotation 13 | 14 | abstract class CurrentTime(val refreshRateSeconds: Long) extends Product { 15 | lazy val srcId: SrcId = this.getClass.getName 16 | } 17 | 18 | abstract class TimeGetter(val currentTime: CurrentTime) extends WithCurrentTime { 19 | def ofA(context: AssembledContext): Option[T_Time] 20 | } 21 | 22 | trait TimeGetters { 23 | def apply(currentTime: CurrentTime): TimeGetter 24 | def all: List[TimeGetter] 25 | } 26 | 27 | type T_Time = ee.cone.c4actor.time.ProtoCurrentTimeConfig.T_Time 28 | } 29 | -------------------------------------------------------------------------------- /micro/kui/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /base_lib/src/main/java/ee/cone/c4actor_kafka_impl/KafkaMessageSender.java: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_kafka_impl; 2 | 3 | import org.apache.kafka.clients.producer.Producer; 4 | import org.apache.kafka.clients.producer.ProducerRecord; 5 | import org.apache.kafka.clients.producer.RecordMetadata; 6 | import org.apache.kafka.common.header.Header; 7 | 8 | import java.util.List; 9 | import java.util.concurrent.CompletableFuture; 10 | import java.util.concurrent.ExecutionException; 11 | import java.util.concurrent.Future; 12 | 13 | public class KafkaMessageSender { 14 | public static Future send( 15 | String topic, 16 | byte[] value, 17 | List
headers, 18 | CompletableFuture> producer 19 | ) throws ExecutionException, InterruptedException { 20 | return producer.get().send(new ProducerRecord<>(topic, 0, new byte[0], value, headers)); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/BigDecimalImpl.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4actor 3 | 4 | import ee.cone.c4proto.{Id, ToByteString, protocol, replaceBy} 5 | 6 | object BigDecimalFactory { 7 | def apply(scale: Int, bytes: okio.ByteString): BigDecimal = 8 | BigDecimal(new java.math.BigDecimal(new java.math.BigInteger(bytes.toByteArray), scale)) 9 | def unapply(value: BigDecimal): Option[(Int,okio.ByteString)] = { 10 | val byteString = ToByteString(value.bigDecimal.unscaledValue.toByteArray) 11 | Option((value.bigDecimal.scale, byteString)) 12 | } 13 | } 14 | 15 | 16 | 17 | trait BigDecimalProtocolAdd { 18 | type BigDecimal = scala.math.BigDecimal 19 | // val BigDecimalFactory = ee.cone.c4actor.BigDecimalFactory 20 | } 21 | 22 | @protocol("BigDecimalApp") object BigDecimalProtocol extends BigDecimalProtocolAdd { 23 | @replaceBy[BigDecimal](BigDecimalFactory) 24 | case class SysBigDecimal(@Id(0x0001) scale: Int, @Id(0x0002) bytes: okio.ByteString) 25 | } 26 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/SnapshotListApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.NextOffset 4 | import ee.cone.c4proto.{Id, protocol} 5 | 6 | trait SnapshotListProtocolAppBase 7 | @protocol("SnapshotListProtocolApp") object SnapshotListRequestProtocol { 8 | @Id(0x36c9) case class S_ListSnapshotsRequest( 9 | @Id(0x36ca) source: String 10 | ) 11 | 12 | @Id(0x36cb) case class S_ListSnapshotsResponse( 13 | @Id(0x36cc) source: String, 14 | @Id(0x36cd) snapshotsInfo: List[N_SnapshotInfoProto] 15 | ) 16 | 17 | case class N_SnapshotInfoProto( 18 | @Id(0x36cf) subDirStr: String, 19 | @Id(0x36d0) offset: String, 20 | @Id(0x36d1) uuid: String, 21 | @Id(0x36d2) raw: Option[N_RawSnapshotInfoProto], 22 | @Id(0x36d5) creationDate: Long 23 | ) 24 | 25 | case class N_RawSnapshotInfoProto( 26 | @Id(0x36d4) relativePath: String 27 | ) 28 | } 29 | 30 | trait ConsumerBeginningOffset { 31 | def get(): NextOffset 32 | } 33 | -------------------------------------------------------------------------------- /c4util/servers.py: -------------------------------------------------------------------------------- 1 | 2 | def http_serve(addr, routes: dict): 3 | from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler 4 | class CallHandler(BaseHTTPRequestHandler): 5 | def do_POST(self): 6 | len_str = self.headers.get('Content-Length') 7 | routes[self.path](b'' if len_str is None else self.rfile.read(int(len_str))) 8 | self.send_response(200) 9 | self.end_headers() 10 | #noinspection PyTypeChecker 11 | ThreadingHTTPServer(addr, CallHandler).serve_forever() 12 | 13 | # noinspection PyTypeChecker 14 | def tcp_serve(addr, on_line, on_fin): 15 | from socketserver import ThreadingTCPServer, StreamRequestHandler 16 | class LogHandler(StreamRequestHandler): 17 | def handle(self): 18 | for line in self.rfile: on_line(line.rstrip(b'\n')) 19 | on_fin() 20 | class LogServer(ThreadingTCPServer): 21 | allow_reuse_address = True 22 | LogServer(addr, LogHandler).serve_forever() 23 | -------------------------------------------------------------------------------- /micro/umon/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from time import monotonic 3 | from os import environ 4 | from prometheus_client import Gauge, start_http_server 5 | from playwright.sync_api import sync_playwright 6 | 7 | def tries(f): 8 | try: return f() 9 | except: return None 10 | 11 | def main(): 12 | SITE = environ["C4MON_SITE"] 13 | ok = Gauge("c4synthetic_ok", "Synthetic OK", ["site"]) 14 | lat = Gauge("c4synthetic_latency_seconds", "Latency", ["site"]) 15 | start_http_server(int(environ["C4METRICS_PORT"])) 16 | page = sync_playwright().start().chromium.launch(headless=True).new_context().new_page() 17 | page.goto(f"https://{SITE}") 18 | while True: 19 | started = monotonic() 20 | ok.labels(SITE).set(1 if tries(lambda: page.wait_for_selector(environ["C4MON_SELECTOR"], timeout=4000)) else 0) 21 | lat.labels(SITE).set(monotonic() - started) 22 | page.wait_for_timeout(30000) 23 | page.reload() 24 | 25 | if __name__ == "__main__": main() -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/HashSearchApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4assemble.Assemble 5 | 6 | class HashSearchFactoryHolder(val value: HashSearch.Factory) 7 | object HashSearch { 8 | 9 | case class Request[Model <: Product](requestId: SrcId, condition: Condition[Model]) 10 | 11 | case class Response[Model <: Product](srcId: SrcId, request: Request[Model], linesHashed: PreHashed[Option[List[Model]]]) extends { 12 | def lines: List[Model] = linesHashed.value.get 13 | } 14 | 15 | trait Factory { 16 | def index[Model <: Product](model: Class[Model]): IndexBuilder[Model] 17 | 18 | def request[Model <: Product](condition: Condition[Model]): Request[Model] 19 | } 20 | 21 | trait IndexBuilder[Model <: Product] { 22 | def add[By <: Product, Field](lens: ProdLensStrict[Model, Field], by: By)( 23 | implicit ranger: Ranger[By, Field] 24 | ): IndexBuilder[Model] 25 | 26 | def assemble: Assemble 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/rdb/RDBExtensionApi.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4actor.rdb 3 | 4 | trait ExternalDBFactory { 5 | def create(wrap: (()=>java.sql.Connection)=>RConnectionPool): RConnectionPool 6 | } 7 | 8 | trait RConnectionPool { 9 | def doWith[T](f: RConnection=>T): T 10 | } 11 | 12 | trait ExternalDBClient { 13 | /** 14 | * Blocking method, which waits for db to be prepared for usage. 15 | * @return RConnectionPool 16 | */ 17 | def getConnectionPool: RConnectionPool 18 | } 19 | 20 | trait RDBBind[R] { 21 | def in(value: String): RDBBind[R] 22 | def in(value: Long): RDBBind[R] 23 | def in(value: Boolean): RDBBind[R] 24 | def call(): R 25 | } 26 | 27 | trait RConnection { 28 | def outUnit(name: String): RDBBind[Unit] 29 | def outLongOption(name: String): RDBBind[Option[Long]] 30 | def outText(name: String): RDBBind[String] 31 | def execute(code: String): Unit 32 | def executeQuery(code: String, cols: List[String], bindList: List[Object]): List[Map[String,Object]] 33 | } 34 | 35 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4gate/deep_session/DeepSessionAttrMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate.deep_session 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4assemble.Assemble 5 | import ee.cone.c4gate.SessionAttrAccessFactory 6 | 7 | trait DeepSessionAttrApp 8 | extends SessionDataProtocolApp 9 | with DeepSessionAttrFactoryImplApp 10 | with DeepSessionDataAssembleApp 11 | 12 | trait SessionDataProtocolAppBase 13 | trait DeepSessionAttrFactoryImplAppBase extends ComponentProviderApp with TxDeepRawDataLensApp { 14 | lazy val deepSessionAttrAccessFactory: DeepSessionAttrAccessFactory = 15 | resolveSingle(classOf[DeepSessionAttrAccessFactory]) 16 | } 17 | trait TxDeepRawDataLensAppBase 18 | 19 | trait DeepSessionDataAssembleApp extends AssemblesApp { 20 | def mortal: MortalFactory 21 | 22 | def userModel: Class[_ <: Product] 23 | 24 | def roleModel: Class[_ <: Product] 25 | 26 | override def assembles: List[Assemble] = 27 | DeepSessionDataAssembles(mortal, userModel, roleModel) ::: super.assembles 28 | } 29 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/PublishApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4actor.{RawCompressor, Context, LEvent} 5 | import ee.cone.c4gate.HttpProtocol.N_Header 6 | import okio.ByteString 7 | 8 | trait PublishFromStringsProvider { 9 | def get: List[(String,String)] 10 | } 11 | 12 | trait PublishMimeTypesProvider { 13 | def get: List[(String,String)] 14 | } 15 | 16 | class PublishFullCompressor(val value: RawCompressor) 17 | 18 | //// 19 | 20 | case class ByPathHttpPublication(path: String, headers: List[N_Header], body: ByteString) 21 | case class ByPathHttpPublicationUntil(path: String, until: Long) 22 | case class PurgePublication(srcId: SrcId) 23 | 24 | trait Publisher { 25 | def publish(publication: ByPathHttpPublication, until: Long=>Long): Seq[LEvent[Product]] 26 | def publish(man: String, publications: List[ByPathHttpPublication]): Context=>Seq[LEvent[Product]] 27 | } 28 | 29 | //// 30 | 31 | trait PublicDirHeaders { 32 | def headers: List[N_Header] 33 | } 34 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4actor/DeadlockTest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4di.c4 4 | 5 | import scala.concurrent.Future 6 | 7 | object DeadlockTest { 8 | case class Rich(){ 9 | lazy val veryRich = VeryRich(this) 10 | lazy val value = 2 11 | lazy val veryRichValue = { 12 | Thread.sleep(300) 13 | println("in Rich") 14 | val res = veryRich.value 15 | println("Rich can not be here") 16 | res 17 | } 18 | } 19 | 20 | case class VeryRich(b: Rich){ 21 | lazy val value = { 22 | Thread.sleep(300) 23 | println("in VeryRich") 24 | val res = b.value 25 | println("VeryRich can not be here") 26 | res 27 | } 28 | } 29 | } 30 | 31 | import DeadlockTest._ 32 | 33 | @c4("DeadlockTestApp") final class DeadlockTest(execution: Execution) extends Executable { 34 | def run(): Unit = { 35 | val b = Rich() 36 | val c = b.veryRich 37 | execution.fatal(Future(b.veryRichValue)(_)) 38 | execution.fatal(Future(c.value)(_)) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /generator/src/main/scala/ee/cone/c4generator/ByPriority.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4generator 2 | 3 | case class PriorityState[K,V](map: Map[K,V], values: List[V], inProcess: Set[K], inProcessList: List[K]) 4 | 5 | class ByPriority[K,V](uses: K=>(List[K],List[V]=>V)) { 6 | private def add(state: PriorityState[K,V], key: K): PriorityState[K,V] = 7 | if(state.map.contains(key)) state else { 8 | if (state.inProcess(key)) throw new Exception(s"${state.inProcessList.mkString("\n")} \nhas $key") 9 | val (useKeys,toValue) = uses(key) 10 | val deeperState = state.copy( 11 | inProcess = state.inProcess + key, 12 | inProcessList = key :: state.inProcessList 13 | ) 14 | val filled: PriorityState[K, V] = useKeys.foldLeft(deeperState)(add) 15 | val value = toValue(useKeys.map(filled.map)) 16 | state.copy(map = filled.map + (key->value), values = value :: filled.values) 17 | } 18 | def apply(items: List[K]): List[V] = 19 | items.foldLeft(PriorityState[K,V](Map.empty[K,V],Nil,Set.empty[K],Nil))(add).values 20 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/DeadlockDetect.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import java.lang.management.{ManagementFactory, ThreadMXBean} 4 | 5 | import ee.cone.c4di.c4 6 | 7 | import scala.annotation.tailrec 8 | 9 | @c4("DeadlockDetectApp") final class DeadlockDetect extends Executable with Early { 10 | @tailrec def iter(bean: ThreadMXBean): Unit = Option(bean.findMonitorDeadlockedThreads()) match { 11 | case None => 12 | Thread.sleep(1000) 13 | iter(bean) 14 | case Some(ids) => 15 | val lines = for { 16 | info <- bean.getThreadInfo(ids,true,true).flatMap(Option(_)) 17 | line <- Array(s"Id: ${info.getThreadId}") ++ 18 | info.getLockedMonitors.map(s=>s"monitor $s locked at depth ${s.getLockedStackDepth} (${s.getLockedStackFrame})") ++ 19 | info.getStackTrace.map(s=>s"call $s") 20 | } yield line 21 | println(lines.map(l=>s"\nDD: $l").mkString) 22 | throw new Exception("Deadlock detected") 23 | } 24 | def run(): Unit = iter(ManagementFactory.getThreadMXBean) 25 | } 26 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4ui/UIExampleMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4actor_kafka_impl._ 5 | import ee.cone.c4actor_logback_impl.BasicLoggingApp 6 | import ee.cone.c4actor_repl_impl.SSHDebugApp 7 | import ee.cone.c4di.c4app 8 | import ee.cone.c4gate._ 9 | import ee.cone.c4gate_akka.AkkaGatewayApp 10 | 11 | trait PublicViewAssembleAppBase 12 | 13 | // TestTxLogApp MergingSnapshotApp SSHDebugApp 14 | @c4app class TestTodoAppBase extends ServerCompApp 15 | with EnvConfigCompApp with VMExecutionApp 16 | with KafkaProducerApp with KafkaConsumerApp 17 | with ParallelObserversApp 18 | with UICompApp 19 | with NoAssembleProfilerCompApp 20 | with ManagementApp with PublishingCompApp 21 | with RemoteRawSnapshotApp 22 | with PublicViewAssembleApp 23 | with ModelAccessFactoryCompApp 24 | with AvailabilityApp 25 | with BasicLoggingApp 26 | with PublisherApp 27 | with SkipWorldPartsApp 28 | with LZ4RawCompressorApp 29 | with AuthProtocolApp 30 | with AuthOperationsApp 31 | with AkkaGatewayApp 32 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_kafka_impl/LZ4Compressor.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_kafka_impl 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4di.c4 6 | import net.jpountz.lz4.{LZ4BlockInputStream, LZ4BlockOutputStream} 7 | import okio.{Buffer, BufferedSource, Okio, RealBufferedSource} 8 | 9 | @c4("LZ4DeCompressorApp") final 10 | case class LZ4DeCompressor() extends DeCompressor with LazyLogging { 11 | def name: String = "lz4" 12 | def deCompress(compressed: BufferedSource): BufferedSource = 13 | new RealBufferedSource(Okio.source(new LZ4BlockInputStream(compressed.inputStream()))) 14 | } 15 | 16 | @c4("LZ4RawCompressorApp") final 17 | case class LZ4RawCompressor() extends RawCompressor { 18 | def name: String = "lz4" 19 | def compress(data: Array[Byte]): Array[Byte] = 20 | FinallyClose(new Buffer) { buffer => 21 | FinallyClose(new LZ4BlockOutputStream(buffer.outputStream(), 32000000)) { lz41 => 22 | lz41.write(data) 23 | } 24 | buffer.readByteArray() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /micro/kui/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN perl install.pl useradd 1979 4 | RUN perl install.pl apt curl ca-certificates xz-utils git python3-venv tini lsof mc 5 | RUN perl install.pl curl https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.9.0/oauth2-proxy-v7.9.0.linux-amd64.tar.gz 6 | RUN perl install.pl curl https://nodejs.org/dist/v22.15.1/node-v22.15.1-linux-x64.tar.xz 7 | RUN perl install.pl curl https://dl.k8s.io/release/v1.33.1/bin/linux/amd64/kubectl && chmod +x /tools/kubectl 8 | RUN perl install.pl curl https://github.com/async-profiler/async-profiler/releases/download/v4.1/async-profiler-4.1-linux-x64.tar.gz 9 | USER c4 10 | ENV PATH=${PATH}:/tools:/tools/oauth:/tools/node/bin 11 | RUN mkdir /c4/c4client && cd /c4/c4client && npm install esbuild@^0.25.4 react@^19.1.0 react-dom@^19.1.0 @tailwindcss/cli@^4.1.7 12 | RUN python3 -m venv /c4/venv && /c4/venv/bin/pip install --no-cache-dir websockets==15.0.1 13 | ENTRYPOINT ["tini","--","/c4/venv/bin/python","-u","-c","from app import main;main()"] 14 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/PreHashingImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4di.c4 4 | 5 | // http://www.artima.com/pins1ed/object-equality.html 6 | @c4("RichDataCompApp") final class PreHashingImpl extends PreHashing { 7 | def wrap[T](value: T): PreHashed[T] = new PreHashedImpl(value.hashCode, value) 8 | } 9 | 10 | final class PreHashedImpl[T](code: Int, val value: T) extends PreHashed[T] { 11 | override def hashCode: Int = code 12 | 13 | override def equals(that: Any): Boolean = { 14 | that match { 15 | case that: PreHashed[_] => value == that.value 16 | case _ => false 17 | } 18 | } 19 | 20 | override def toString: String = s"PreHashed(${value.toString})" 21 | } 22 | 23 | /** *********** 24 | * try later: 25 | * override val hashCode: Int = scala.util.hashing.MurmurHash3.productHash(this) 26 | * class A(val b: Int)(val c: Int=b+b) extends E { private val d = b + c } 27 | * order: b, c, E-super, d 28 | * so to avoid possible non-initialized this, hashCode should be "c"? 29 | * pr in abstract class extending Product? 30 | * *************/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/conecenter/c4proto.svg?branch=master)](https://travis-ci.org/conecenter/c4proto) 2 | 3 | # c4proto 4 | This is a microservice framework based on eventsourcing ideas. 5 | Kafka is used by microservices to exchange messages and store application state changes. 6 | Protocol buffers are used to serialize messages (`c4proto-*`): 7 | - supports subset of protocol buffers 8 | - supports BigDecimal in messages and is extensible to support custom classes 9 | - messages are described by annotations on case classes 10 | - uses small wire-runtime 11 | - uses scalameta to generate protocol buffer adapters 12 | 13 | Application state changes are consumed to in-memory immutable object graph (read model) (`c4actor-*`). 14 | - Changes are propagated through the graph according to dependency rules. 15 | - Propagation forms data structures optimized for different "requests". 16 | 17 | To compile/run example: `cd dev_server && sh example.sh`. 18 | 19 | To look inside: 20 | - `docker exec -it devserver_main_1 bash` 21 | - `tail -f /var/log/syslog` 22 | - browse http://127.0.0.10/todo-app.html#todo 23 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/DefaultModelApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | 5 | trait ModelFactory extends Product { 6 | def create[P<:Product](valueClass: Class[P])(srcId: SrcId): P = process[P](valueClass.getName, None, srcId) 7 | def create[P<:Product](className: String)(srcId: SrcId): P = process[P](className, None, srcId) 8 | def changeSrcId[P<:Product](valueClass: Class[P])(srcId: SrcId)(model: P): P = change[P](valueClass.getName, model, srcId) 9 | def changeSrcId[P<:Product](className: String)(srcId: SrcId)(model: P): P = change[P](className, model, srcId) 10 | protected def change[P<:Product](className: String, base: P, srcId: SrcId): P 11 | protected def process[P<:Product](className: String, basedOn: Option[P], srcId: SrcId): P 12 | } 13 | 14 | abstract class GeneralDefaultModelInitializer(val valueClass: Class[_], specInit: Nothing=>Any) { 15 | def init[T](value: T): T = specInit.asInstanceOf[T=>T](value) 16 | } 17 | abstract class DefaultModelInitializer[P](valueClass: Class[P], init: P=>P) extends GeneralDefaultModelInitializer(valueClass,init) 18 | -------------------------------------------------------------------------------- /vault.py: -------------------------------------------------------------------------------- 1 | import http.client 2 | import json 3 | import pathlib 4 | import os 5 | 6 | 7 | def main(): 8 | vault_prefix = "/c4/vault/" 9 | env_vals = {v for k, v in os.environ.items() if k.startswith("C4") and v.startswith(vault_prefix)} 10 | if not env_vals: return 11 | kube_token = pathlib.Path("/var/run/secrets/kubernetes.io/serviceaccount/token").read_text() 12 | conn = http.client.HTTPConnection(os.environ["C4VAULT_HOST_PORT"]) 13 | conn.request("POST", "/v1/auth/kubernetes/login", json.dumps({"jwt": kube_token, "role": "app"})) 14 | vault_token = json.loads(conn.getresponse().read())["auth"]["client_token"] 15 | for dir in sorted({"/".join(v.split("/")[:-1]) for v in env_vals}): 16 | secret_path = dir[len(vault_prefix):] 17 | pathlib.Path(dir).mkdir(parents=True) 18 | conn.request("GET", f"/v1/kv/data/{secret_path}", headers={"X-Vault-Token": vault_token}) 19 | for key, content in json.loads(conn.getresponse().read())["data"]["data"].items(): 20 | pathlib.Path(f"{dir}/{key}").write_text(content, encoding='utf-8', errors='strict') 21 | 22 | 23 | main() 24 | -------------------------------------------------------------------------------- /client/src/main/receiver.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from "./react" 2 | import { EnqueuePatch, Identity, identityAt, patchFromValue } from "./util" 3 | 4 | const deleteIdOf = identityAt("delete") 5 | type MessageReceiver = (value: string) => void 6 | type ReceiverBranchContext = { enqueue: EnqueuePatch, isRoot: boolean } 7 | type ToAlienMessageComponentsArgs = { messageReceiver: MessageReceiver, useBranch: ()=>ReceiverBranchContext } 8 | export const ToAlienMessageComponents = ({messageReceiver,useBranch}:ToAlienMessageComponentsArgs) => { 9 | const ToAlienMessagesElement = ({messages}:{messages?:React.ReactElement[]}) => messages??[] 10 | const ToAlienMessageElement = ({ identity, value } : { identity: Identity, value: string }) => { 11 | const {enqueue,isRoot} = useBranch() 12 | useEffect(()=>{ 13 | if(!isRoot) return undefined 14 | enqueue(deleteIdOf(identity), patchFromValue("")) 15 | return () => messageReceiver(value) // local send at-most-once 16 | }, [enqueue,isRoot,identity,value]) 17 | return [] 18 | } 19 | return {ToAlienMessagesElement,ToAlienMessageElement} 20 | } 21 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4gate/TestTxTransform.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor.Types.SrcId 5 | import ee.cone.c4actor._ 6 | import ee.cone.c4assemble.Types.{Each, Values} 7 | import ee.cone.c4assemble.{Assemble, assemble, c4assemble} 8 | import ee.cone.c4di.c4multi 9 | import ee.cone.c4gate.HttpProtocol.S_HttpRequest 10 | 11 | @c4assemble("TestTxTransformApp") class TestDelayAssembleBase( 12 | factory: TestDelayHttpHandlerFactory, 13 | ){ 14 | def joinTestHttpHandler( 15 | key: SrcId, 16 | req: Each[S_HttpRequest] 17 | ): Values[(SrcId, TxTransform)] = 18 | List(WithPK(factory.create(req.srcId, req))) 19 | } 20 | 21 | @c4multi("TestTxTransformApp") final case class TestDelayHttpHandler(srcId: SrcId, req: S_HttpRequest)( 22 | txAdd: LTxAdd, 23 | ) extends TxTransform with LazyLogging { 24 | def transform(local: Context): Context = { 25 | logger.info(s"start handling $srcId") 26 | concurrent.blocking{ 27 | Thread.sleep(1000) 28 | } 29 | logger.info(s"finish handling $srcId") 30 | txAdd.add(LEvent.delete(req))(local) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4ui/UIMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor_branch.BranchApp 4 | import ee.cone.c4gate._ 5 | import ee.cone.c4di.{c4, provide} 6 | import ee.cone.c4vdom._ 7 | import ee.cone.c4vdom_impl._ 8 | 9 | 10 | 11 | 12 | trait UICompAppBase extends AlienExchangeCompApp with BranchApp with SessionUtilApp with EventLogApp 13 | 14 | trait AlienExchangeCompAppBase extends AlienProtocolApp with HttpProtocolApp 15 | 16 | @c4("UICompApp") final class VDomProvider { 17 | private lazy val diff = new DiffImpl(MapVDomValueImpl,WasNoValueImpl) 18 | private lazy val vDomFactory = new VDomFactoryImpl(MapVDomValueImpl) 19 | private lazy val childPairFactory = new ChildPairFactoryImpl(vDomFactory) 20 | @provide def vDomFactoryPr: Seq[VDomFactory] = List(vDomFactory) 21 | @provide def childPairFactoryPr: Seq[ChildPairFactory] = List(childPairFactory) 22 | @provide def tagJsonUtilsPr: Seq[TagJsonUtils] = List(TagJsonUtilsImpl) 23 | @provide def vDomHandlerFactoryPr: Seq[VDomHandler] = 24 | List(new VDomHandlerImpl(diff,FixDuplicateKeysImpl,JsonToStringImpl,WasNoValueImpl)) 25 | @provide def vDomResolverPr: Seq[VDomResolver] = List(VDomResolverImpl) 26 | } 27 | -------------------------------------------------------------------------------- /assemble_log2html.pl: -------------------------------------------------------------------------------- 1 | use strict; 2 | use List::Util qw[min max]; 3 | 4 | my @res; 5 | for(){ 6 | m{\bms\s+\[(\d+)\d{6}/(\d+)\d{6}/(\d+)\d{6}/(\d+)\d{6}\]} or next; 7 | push @res, { tm=>[$1,$2,$3,$4], hint=>$_ }; 8 | } 9 | my $from = min(map{@{$$_{tm}}} @res); 10 | my $to = max(map{@{$$_{tm}}} @res); 11 | my $ppu = 2000/($to-$from); 12 | my $draw = sub{ 13 | my($n,$l_from,$l_to,$color,$hint)=@_; 14 | my $left = int(($l_from-$from)*$ppu); 15 | my $w = int(($l_to-$l_from)*$ppu); 16 | my $top = $n * 3; 17 | qq[
$hint
] 18 | }; 19 | 20 | my @pres = map{ 21 | my $e = $res[$_]; 22 | ( 23 | &$draw($_,@{$res[$_]{tm}}[0,1],"red",$res[$_]{hint}), 24 | &$draw($_,@{$res[$_]{tm}}[1,2],"green",$res[$_]{hint}), 25 | &$draw($_,@{$res[$_]{tm}}[2,3],"blue",$res[$_]{hint}), 26 | ) 27 | } 0..$#res; 28 | print "".join("\n",@pres); 44 | -------------------------------------------------------------------------------- /elector.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const http = require('http'); 4 | 5 | const locks = {} 6 | const lock = (url,owner,period) => { 7 | const now = Date.now() 8 | const wasLock = locks[url] 9 | if(owner && period && (!wasLock || wasLock.owner === owner || wasLock.until < now)){ 10 | if(!wasLock || wasLock.owner !== owner) console.log(`${url} locked by ${owner}`) 11 | locks[url] = { owner, until: now+period } 12 | return true 13 | } 14 | } 15 | 16 | const server = http.createServer((req, res) => { 17 | const owner = req.headers["x-r-lock-owner"] 18 | const period = parseInt(req.headers["x-r-lock-period"]) 19 | res.statusCode = req.method === "POST" && lock(req.url,owner,period) ? 200 : 400 20 | res.end() 21 | }) 22 | 23 | server.listen(process.env.C4HTTP_PORT, "0.0.0.0", () => { 24 | console.log("Server running",server.address()); 25 | }) 26 | 27 | setInterval(()=>{ 28 | const now = Date.now() 29 | for(let url in locks) if(locks[url].until < now) delete locks[url] 30 | console.log(Object.keys(locks).map(url=>url.substring(url.length-3)).join(" ")) 31 | },1000) 32 | 33 | // curl -v kc-elector2-dev-1.kc-elector2-dev:1080 -v -XPOST -H 'x-r-lock-owner: he' -H 'x-r-lock-period: 5000' 34 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4vdom/CanvasPathImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4vdom 2 | 3 | import ee.cone.c4vdom.Types.VDomKey 4 | 5 | case class PathFactoryImpl[Context]( 6 | child: ChildPairFactory, pathToJson: CanvasToJson 7 | ) extends PathFactory { 8 | def path(key: VDomKey, children: ChildPair[OfPath]*): ChildPair[OfPathParent] = 9 | path(key, children.toList) 10 | def path(key: VDomKey, children: List[ChildPair[OfPath]]): ChildPair[OfPathParent] = 11 | child[OfPathParent]( 12 | key, 13 | PartPath[Context](children.collect{ case a:PathAttr=>a })(pathToJson), 14 | children.filterNot(_.isInstanceOf[PathAttr]) 15 | ) 16 | } 17 | 18 | case class PartPath[Context](attrs:List[PathAttr])( 19 | pathToJson: CanvasToJson 20 | ) extends VDomValue with Receiver[Context] { 21 | def receive: VDomMessage => Context => Context = message => message.header("x-r-action") match { 22 | case "clickColor" => 23 | attrs.collect{case h:ClickPathHandler[_]=>h}.head.handleClick.asInstanceOf[Context=>Context] 24 | case _ => throw new Exception("Unknown action type") 25 | } 26 | def appendJson(builder: MutableJsonBuilder): Unit = 27 | pathToJson.appendPathJson(attrs,builder) 28 | } 29 | -------------------------------------------------------------------------------- /c4dep.gate.json: -------------------------------------------------------------------------------- 1 | [ 2 | ["C4EXT", "base_server.ee.cone.c4gate_akka", "com.typesafe.akka:akka-stream_2.13:2.5.25" ], 3 | ["C4EXT", "base_server.ee.cone.c4gate_akka", "com.typesafe.akka:akka-http-core_2.13:10.1.10" ], 4 | ["#C4EXT", "base_server.ee.cone.c4gate_akka", "com.typesafe.akka:akka-stream_2.13:2.6.3" ], 5 | ["#C4EXT", "base_server.ee.cone.c4gate_akka", "com.typesafe.akka:akka-http-core_2.13:10.1.11" ], 6 | 7 | ["C4DEP", "base_server.ee.cone.c4gate_server", "base_lib.ee.cone.c4actor_xml" ], 8 | ["C4DEP", "base_server.ee.cone.c4gate_server", "base_lib.ee.cone.c4gate" ], 9 | ["C4DEP", "base_server.ee.cone.c4gate_server", "base_lib.ee.cone.c4actor_kafka_impl" ], 10 | ["C4DEP", "base_server.ee.cone.c4gate_server", "base_lib.ee.cone.c4actor_logback_impl" ], 11 | ["C4DEP", "base_server.ee.cone.c4gate_akka", "base_server.ee.cone.c4gate_server" ], 12 | ["#C4DEP", "base_server.ee.cone.c4gate_akka", "base_lib.ee.cone.c4actor_repl_impl" ], 13 | ["#C4DEP", "base_server.ee.cone.c4gate_akka_s3", "base_server.ee.cone.c4gate_akka" ], 14 | ["#C4DEP", "base_server.ee.cone.c4gate_akka_s3", "base_server.ee.cone.c4gate_server" ], 15 | ["#C4DEP", "base_server.ee.cone.c4gate_akka_s3", "base_lib.ee.cone.c4actor_s3_minio" ] 16 | ] -------------------------------------------------------------------------------- /base_lib/src/main/java/ee/cone/c4assemble/gen.pl: -------------------------------------------------------------------------------- 1 | use strict; 2 | 3 | my $m = 9; 4 | 5 | my $get_method = sub{ 6 | my($n,$t)=@_; 7 | my $st = $t=~/(\w+)$/ ? $1 : die; 8 | qq^ 9 | public interface Handler$n { 10 | public void handle${st}s(^.join(", ",map{"$t a$_"}0..$_-1).q^); 11 | } 12 | public static void foreach(^.join("",map{"$t\[] a$_, "}0..$n-1).qq^Handler$n handler){ 13 | ^.join("",map{"for (int i$_ = 0; i$_",$path and print FF $content and close FF or die $!; 23 | }; 24 | 25 | my $put_for_class = sub{ 26 | my($cl,$t)=@_; 27 | my $content = qq^package ee.cone.c4assemble;\npublic class $cl {^. 28 | join("",map{ &$get_method($_,$t) }1..9). 29 | q^}^; 30 | &$put("$cl.java",$content); 31 | }; 32 | 33 | &$put_for_class(ProdMultiFor=>"scala.Product"); 34 | &$put_for_class(PartMultiFor=>"MultiForPart"); 35 | &$put("MultiForPart.java",qq^package ee.cone.c4assemble; 36 | public interface MultiForPart { 37 | boolean isChanged(); 38 | scala.Product[] items(); 39 | } 40 | ^); -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4gate/KafkaLatTestApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4assemble.Single 6 | import ee.cone.c4di.c4 7 | 8 | import scala.annotation.tailrec 9 | import scala.collection.immutable.Seq 10 | 11 | 12 | class TestQRecordImpl(val topic: TxLogName, val value: Array[Byte], val headers: Seq[RawHeader]) extends QRecord 13 | @c4("KafkaLatTestApp") final class TestRootProducerImpl( 14 | qMessages: QMessages, 15 | ) extends Executable with LazyLogging { 16 | def run(): Unit = { 17 | iteration() 18 | } 19 | @tailrec private def iteration(): Unit = { 20 | val offset = qMessages.doSend(Nil) 21 | logger.info(s"pushed $offset") 22 | Thread.sleep(1000) 23 | iteration() 24 | } 25 | } 26 | 27 | 28 | @c4("KafkaLatTestApp") final class TestRootConsumerImpl(consuming: Consuming) extends Executable with LazyLogging { 29 | def run(): Unit = { 30 | consuming.process("0" * OffsetHexSize(), consumer => iteration(consumer)) 31 | } 32 | @tailrec private def iteration(consumer: Consumer): Unit = { 33 | val events = consumer.poll() 34 | logger.info(s"poll-ed ${events.size}") 35 | iteration(consumer) 36 | } 37 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/HttpUtilApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import okio.ByteString 4 | 5 | case class HttpResponse(status: Int, headers: Map[String, List[String]], body: ByteString) 6 | 7 | trait HttpUtil { 8 | def get(url: String, headers: List[(String, String)]): HttpResponse 9 | def post(url: String, headers: List[(String, String)]): Unit 10 | def post(url: String, headers: List[(String, String)], body: ByteString, timeOut: Option[Int], expectCode: Int*): Unit 11 | def put(url: String, headers: List[(String, String)], body: ByteString, timeOut: Option[Int]): Int 12 | def put(url: String, headers: List[(String, String)], body: ByteString): Int 13 | } 14 | object HttpUtil { 15 | sealed trait HttpMethod { 16 | def ==: (that: String): Boolean = that == this.toString 17 | } 18 | object HttpMethod { 19 | case object PUT extends HttpMethod 20 | case object POST extends HttpMethod 21 | case object GET extends HttpMethod 22 | case object OPTIONS extends HttpMethod 23 | case object HEAD extends HttpMethod 24 | case object PATCH extends HttpMethod 25 | case object DELETE extends HttpMethod 26 | case object TRACE extends HttpMethod 27 | case object CONNECT extends HttpMethod 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ConditionApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | trait Condition[-Model] extends Product { 4 | def check(model: Model): Boolean 5 | } 6 | 7 | trait ModelConditionFactory[Model] { 8 | def of[OtherModel<:Product]: ModelConditionFactory[OtherModel] 9 | def ofWithCl[OtherModel <: Product]: Class[OtherModel] => ModelConditionFactory[OtherModel] 10 | def intersect: (Condition[Model],Condition[Model]) => Condition[Model] 11 | def union: (Condition[Model],Condition[Model]) => Condition[Model] 12 | def any: Condition[Model] 13 | def leaf[By<:Product,Field](lens: ProdGetter[Model,Field], by: By, byOptions: List[AbstractMetaAttr])( 14 | implicit check: ConditionCheck[By,Field] 15 | ): Condition[Model] 16 | def filterMetaList[Field]: ProdGetter[Model,Field] => List[AbstractMetaAttr] 17 | } 18 | trait ConditionCheck[By<:Product,Field] extends Product { 19 | def prepare: List[AbstractMetaAttr] => By => By 20 | def check: By => Field => Boolean 21 | /* 22 | Checks if incoming By has default value and equals true always 23 | */ 24 | def defaultBy: Option[By => Boolean] 25 | } 26 | trait ProdCondition[By<:Product,Model] extends Condition[Model] { 27 | def by: By 28 | def metaList: List[AbstractMetaAttr] 29 | } 30 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4ui/dep/GateAskMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui.dep 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4actor.dep._ 5 | import ee.cone.c4actor.dep.request.ContextIdRequestProtocolApp 6 | import ee.cone.c4actor.dep_impl.AskByPKsApp 7 | import ee.cone.c4gate.SessionDataProtocol.U_RawSessionData 8 | import ee.cone.c4gate.deep_session.DeepSessionDataProtocol.{U_RawRoleData, U_RawUserData} 9 | import ee.cone.c4gate.deep_session.TxDeepRawDataLensApp 10 | 11 | trait SessionAttrAskUtility { 12 | def sessionAttrAskFactory: SessionAttrAskFactory 13 | } 14 | 15 | trait CurrentTimeAskUtility { 16 | def currentTimeAskFactory: CurrentTimeAskFactory 17 | } 18 | 19 | trait SessionAttrAskCompAppBase extends TxDeepRawDataLensApp 20 | 21 | trait SessionAttrAskMix 22 | extends SessionAttrAskCompApp 23 | with ContextIdRequestProtocolApp 24 | with ComponentProviderApp { 25 | lazy val sessionAttrAskFactory: SessionAttrAskFactory = resolveSingle(classOf[SessionAttrAskFactory]) 26 | } 27 | 28 | trait CurrentTimeAskCompAppBase 29 | 30 | trait CurrentTimeAskMix extends CurrentTimeAskUtility with CurrentTimeAskCompApp with ComponentProviderApp { 31 | lazy val currentTimeAskFactory: CurrentTimeAskFactory = resolveSingle(classOf[CurrentTimeAskFactory]) 32 | } 33 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/Laboratory.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | 5 | object Laboratory { 6 | def main(args: Array[String]): Unit = { 7 | assert(0 == 1, "LUL") 8 | val world = for{ 9 | i <- 1 to 50000 10 | } yield A(i.toString, i) 11 | val list1 = world.slice(0, 20000).toList 12 | val list2 = world.slice(10000,50000).toList 13 | val list3 = world.slice(20000,350000).toList 14 | val list4 = world.slice(35000,49000).toList 15 | val list5 = world.slice(0,50000).toList 16 | 17 | TimeColored("r", "test") { 18 | println(MergeBySrcId(scala.collection.immutable.Seq(list1, list2, list3, list4, list5)).map(_.srcId).distinct.size) 19 | } 20 | 21 | H().printList 22 | } 23 | 24 | case class A(srcId: SrcId, value: Int) 25 | } 26 | 27 | trait A { 28 | def list: List[Product] = Nil 29 | } 30 | 31 | trait B extends A { 32 | override def list: List[Product] = (1, 2) :: super.list 33 | } 34 | 35 | trait D extends B { 36 | override def list: List[Product] = (1, 3) :: super.list 37 | } 38 | 39 | trait E extends B { 40 | override def list: List[Product] = (1, 4) :: super.list 41 | } 42 | 43 | case class H() extends D with E { 44 | def printList = println(list) 45 | } 46 | 47 | -------------------------------------------------------------------------------- /micro/kui/kube_util.py: -------------------------------------------------------------------------------- 1 | 2 | from subprocess import Popen, PIPE 3 | from json import loads 4 | from functools import partial 5 | 6 | def init_kube_resource_watchers(mut_resources, contexts, kcp): 7 | def watcher(context, api, kind): 8 | kube_context = context["name"] 9 | cmd = (*kcp,kube_context,"get","--raw",f'/{api}/{kind}?watch') 10 | with Popen(cmd, text=True, stdout=PIPE) as proc: 11 | mut_state = {} 12 | mut_resources[(kind, kube_context)] = mut_state 13 | for line in proc.stdout: 14 | ev = loads(line) 15 | name = ev["object"]["metadata"]["name"] 16 | match ev["type"]: 17 | case "ADDED" | "MODIFIED": mut_state[name] = ev["object"] #,"kube_context":kube_context,"key":f'{kube_context}~{name}'} 18 | case "DELETED": mut_state.pop(name, None) 19 | return [ 20 | d 21 | for c in contexts 22 | for d in [ 23 | #partial(watcher, c, "api/v1", "nodes"), 24 | partial(watcher, c, f"api/v1/namespaces/{c["ns"]}", "pods"), 25 | partial(watcher, c, f"api/v1/namespaces/{c["ns"]}", "services"), 26 | partial(watcher, c, f"apis/networking.k8s.io/v1/namespaces/{c["ns"]}", "ingresses"), 27 | ] 28 | ] 29 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4gate/ConsumerExamplesMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4actor_kafka_impl.{KafkaConsumerApp, KafkaProducerApp, LZ4DeCompressorApp} 5 | import ee.cone.c4actor_logback_impl.BasicLoggingApp 6 | import ee.cone.c4di.c4app 7 | import ee.cone.c4actor_xml.S3ListerApp 8 | 9 | @c4app class KafkaLatTestAppBase extends EnvConfigCompApp with VMExecutionApp with NoAssembleProfilerCompApp 10 | with ExecutableApp with RichDataCompApp 11 | with KafkaProducerApp with KafkaConsumerApp 12 | 13 | trait TestServerApp extends EnvConfigCompApp with VMExecutionApp with NoAssembleProfilerCompApp 14 | with ServerCompApp with BasicLoggingApp 15 | with KafkaProducerApp with KafkaConsumerApp 16 | with RemoteRawSnapshotApp 17 | with PublisherApp 18 | 19 | @c4app class TestConsumerAppBase extends TestServerApp 20 | with ManagementApp 21 | with AlienProtocolApp 22 | with ParallelObserversApp 23 | 24 | @c4app class HiRateTxAppBase extends TestServerApp with ParallelObserversApp 25 | 26 | trait TestTxTransformAppBase extends TestServerApp 27 | @c4app class TestParallelApp extends TestTxTransformApp with ParallelObserversApp 28 | 29 | trait LongHungryAppBase 30 | 31 | @c4app class TestParallelExAppBase extends TestServerApp with ParallelObserversApp -------------------------------------------------------------------------------- /base_server/src/main/scala/ee/cone/c4gate_server/ServerApi.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4gate_server 3 | 4 | import ee.cone.c4actor.Types.{LEvents, NextOffset} 5 | import ee.cone.c4actor._ 6 | import ee.cone.c4gate.HttpProtocol._ 7 | 8 | import scala.concurrent.{ExecutionContext, Future} 9 | 10 | // inner (TxTr-like) handler api 11 | case class RHttpResponse(response: S_HttpResponse, events: LEvents) 12 | object RHttpTypes { 13 | type RHttpHandler = (S_HttpRequest,Context)=>RHttpResponse 14 | type RHttpHandlerCreate = RHttpHandler=>RHttpHandler 15 | } 16 | 17 | // outer handler api 18 | case class FHttpRequest(method: String, path: String, rawQueryString: Option[String], headers: List[N_Header], body: okio.ByteString) 19 | trait FHttpHandler { 20 | def handle(request: FHttpRequest): S_HttpResponse 21 | } 22 | 23 | trait RHttpResponseFactory { 24 | def directResponse(request: S_HttpRequest, patch: S_HttpResponse=>S_HttpResponse): RHttpResponse 25 | def deferredResponse(request: S_HttpRequest, patch: S_HttpResponse=>S_HttpResponse, events: LEvents): RHttpResponse 26 | } 27 | 28 | trait AlienExchangeState extends Product 29 | trait AlienUtil { 30 | def read(state: AlienExchangeState): (AlienExchangeState, String) 31 | def send(value: String): AlienExchangeState 32 | def stop(state: AlienExchangeState): Unit 33 | } 34 | -------------------------------------------------------------------------------- /client/src/main/sync-hooks.ts: -------------------------------------------------------------------------------- 1 | 2 | import {useEffect,useContext,createContext,useState,useCallback} from "./react" 3 | import {EnqueuePatch,Patch,UnsubmittedPatch,UseSync} from "./util" 4 | 5 | const NoContext = createContext(0) 6 | export const AckContext = createContext(0) 7 | AckContext.displayName = "AckContextProto" 8 | 9 | const nonMerged = (ack: number) => (aPatch: Patch) => !(aPatch && aPatch.index <= ack) 10 | 11 | type SyncBranchContext = { enqueue: EnqueuePatch } 12 | export const UseSyncMod: (useBranch: ()=>SyncBranchContext) => UseSync = useBranch => identity => { 13 | const [patches,setPatches] = useState([]) 14 | const {enqueue} = useBranch() 15 | const enqueuePatch = useCallback((aPatch: UnsubmittedPatch) => { 16 | const index = enqueue(identity, aPatch) 17 | setPatches(aPatches=>[...aPatches,{...aPatch, identity, index, at: Date.now()}]) 18 | },[enqueue,identity]) 19 | const ack = useContext(patches.length>0 ? AckContext : NoContext) 20 | useEffect(()=>{ 21 | setPatches(aPatches => { 22 | if(aPatches.every(nonMerged(ack))) return aPatches 23 | aPatches.forEach(p=>nonMerged(ack)(p) || p.onAck && p.onAck()) 24 | return aPatches.filter(nonMerged(ack)) 25 | }) 26 | },[ack]) 27 | return [patches,enqueuePatch] 28 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/AuthOperationsImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4di.c4 4 | import ee.cone.c4gate.AuthProtocol.N_SecureHash 5 | import ee.cone.c4proto.ToByteString 6 | 7 | import java.security.SecureRandom 8 | import javax.crypto.SecretKeyFactory 9 | import javax.crypto.spec.PBEKeySpec 10 | 11 | @c4("AuthOperationsApp") final class AuthOperationsImpl extends AuthOperations { 12 | private def generateSalt(size: Int): okio.ByteString = { 13 | val random = new SecureRandom() 14 | val salt = new Array[Byte](size) 15 | random.nextBytes(salt) 16 | ToByteString(salt) 17 | } 18 | private def pbkdf2(password: String, template: N_SecureHash): N_SecureHash = { 19 | val spec = new PBEKeySpec(password.toCharArray, template.salt.toByteArray, template.iterations, template.hashSizeInBytes * 8) 20 | val skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1") 21 | template.copy(hash=ToByteString(skf.generateSecret(spec).getEncoded)) 22 | } 23 | def createHash(password: String, userHashOpt: Option[N_SecureHash]): N_SecureHash = 24 | pbkdf2(password, userHashOpt.getOrElse(N_SecureHash(64000, 18, generateSalt(24), okio.ByteString.EMPTY))) 25 | def verify(password: String, correctHash: N_SecureHash): Boolean = 26 | correctHash == pbkdf2(password, correctHash) 27 | } 28 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4vdom_impl/VDomSync.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4vdom_impl 2 | 3 | import ee.cone.c4vdom.{JsonValueAdapter, MutableJsonBuilder, OnChangeMode, TagJsonUtils} 4 | import ee.cone.c4vdom.OnChangeMode._ 5 | 6 | object TagJsonUtilsImpl extends TagJsonUtils { 7 | def appendValue(builder: MutableJsonBuilder, value: String): Unit = 8 | builder.append("value").append(value) 9 | 10 | @deprecated def appendOnChange(builder: MutableJsonBuilder, value: String, deferSend: Boolean, needStartChanging: Boolean): Unit = { 11 | val mode = if(!deferSend) Send else if(needStartChanging) SendFirst else Defer 12 | appendInputAttributes(builder, value, mode) 13 | } 14 | 15 | def appendInputAttributes(builder: MutableJsonBuilder, value: String, mode: OnChangeMode): Unit = { 16 | appendValue(builder, value) 17 | if(mode.value.nonEmpty) 18 | builder.append("onChange").append(mode.value) // ?todo: send on blur anyway 19 | } 20 | 21 | def jsonValueAdapter[T](inner: (T, MutableJsonBuilder) => Unit): JsonValueAdapter[T] = 22 | new JsonValueAdapter[T] { 23 | def appendJson(value: T, builder: MutableJsonBuilder): Unit = inner(value, builder) 24 | } 25 | } 26 | 27 | case object WasNoValueImpl extends WasNoVDomValue { 28 | def appendJson(builder: MutableJsonBuilder): Unit = Never() 29 | } 30 | -------------------------------------------------------------------------------- /run.pl: -------------------------------------------------------------------------------- 1 | 2 | ### here is script to run different containers in runtime/production where most of sources do not present 3 | 4 | use strict; 5 | 6 | my $exec = sub{ print join(" ",@_),"\n"; exec @_; die 'exec failed' }; 7 | sub sy{ print join(" ",@_),"\n"; system @_ and die $?; } 8 | 9 | my @tasks; 10 | 11 | my $serve = sub{ 12 | sy("python3","-u","vault.py"); 13 | sy("perl","ceph.pl"); 14 | $ENV{JAVA_TOOL_OPTIONS} = join " ", $ENV{JAVA_TOOL_OPTIONS}, 15 | "-XX:+ExitOnOutOfMemoryError", 16 | "-XX:+UnlockDiagnosticVMOptions", "-XX:GCLockerRetryAllocationCount=32", 17 | "-XX:MaxGCPauseMillis=200", "-XX:GCTimeRatio=1", "-XX:MinHeapFreeRatio=15", "-XX:MaxHeapFreeRatio=50", 18 | "-XX:+UseStringDeduplication"; 19 | # https://www.javacodegeeks.com/2017/11/minimize-java-memory-usage-right-garbage-collector.html 20 | # with G1/ZGC unused RAM is released back to OS 21 | # G1 gets many GCLocker oom errors on ubuntu 20.04, so we tried ZGC, but it was too hungry, then GCLockerRetryAllocationCount was found 22 | local $ENV{C4PUBLIC_PATH} = "htdocs"; 23 | local $ENV{CLASSPATH} = "app/*"; # join ":", sort ; 24 | &$exec("sh", "serve.sh"); 25 | }; 26 | 27 | push @tasks, [main=>sub{&$serve()}]; 28 | 29 | my($cmd,@args)=@ARGV; 30 | $cmd eq $$_[0] and $$_[1]->(@args) for @tasks; 31 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/LEventTransform.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.CollectiveTransformProtocol.D_CollectiveTransformMeta 4 | import ee.cone.c4assemble.Types.Values 5 | import ee.cone.c4di.c4multi 6 | import ee.cone.c4proto.{Id, protocol} 7 | 8 | import scala.collection.immutable.Seq 9 | 10 | trait LEventTransform extends Product { 11 | def lEvents(local: Context): Seq[LEvent[Product]] 12 | 13 | def leventsDescription: String = this.getClass.getName 14 | } 15 | 16 | trait CollectiveTransformAppBase 17 | @c4multi("CollectiveTransformApp") final case class CollectiveTransform(srcId: String, events: Values[LEventTransform])( 18 | txAdd: LTxAdd, 19 | ) extends TxTransform { 20 | def transform(local: Context): Context = 21 | txAdd.add(events.flatMap(_.lEvents(local)))(InsertOrigMeta(D_CollectiveTransformMeta(events.map(_.leventsDescription).toList) :: Nil)(local)) 22 | } 23 | 24 | object InsertOrigMeta { 25 | def apply(origs: List[Product]): Context => Context = 26 | TxTransformOrigMetaKey.set(origs.map(MetaAttr)) 27 | } 28 | 29 | trait CollectiveTransformProtocolAppBase 30 | @protocol("CollectiveTransformProtocolApp") object CollectiveTransformProtocol { 31 | 32 | @Id(0x0ab0) case class D_CollectiveTransformMeta( 33 | @Id(0x0ab1) transforms: List[String] 34 | ) 35 | 36 | } 37 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4assemble/ByPriorityImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4assemble 2 | 3 | import ee.cone.c4di.c4 4 | 5 | import scala.collection.immutable.Map 6 | 7 | @c4("AssembleApp") final class ByPriorityImpl extends ByPriority { 8 | def byPriority[K,V](uses: K=>(List[K],List[V]=>V)): List[K] => List[V] = 9 | new ByPriorityBuilder[K,V](uses).apply 10 | } 11 | 12 | case class PriorityState[K,V](map: Map[K,V], values: List[V], inProcess: Set[K], inProcessList: List[K]) 13 | 14 | class ByPriorityBuilder[K,V](uses: K=>(List[K],List[V]=>V)) { 15 | private def add(state: PriorityState[K,V], key: K): PriorityState[K,V] = 16 | if(state.map.contains(key)) state else { 17 | if (state.inProcess(key)) throw new Exception(s"${state.inProcessList.mkString("\n")} \nhas $key") 18 | val (useKeys,toValue) = uses(key) 19 | val deeperState = state.copy( 20 | inProcess = state.inProcess + key, 21 | inProcessList = key :: state.inProcessList 22 | ) 23 | val filled: PriorityState[K, V] = useKeys.foldLeft(deeperState)(add) 24 | val value = toValue(useKeys.map(filled.map)) 25 | state.copy(map = filled.map + (key->value), values = value :: filled.values) 26 | } 27 | def apply(items: List[K]): List[V] = 28 | items.foldLeft(PriorityState[K,V](Map.empty[K,V],Nil,Set.empty[K],Nil))(add).values 29 | } 30 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/SessionAttrApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4actor.Types.SrcId 5 | import ee.cone.c4proto.Id 6 | 7 | object SessionAttr { 8 | def apply[B](id: Id, cl: Class[B], values: AbstractMetaAttr*): SessionAttr[B] = 9 | SessionAttr( 10 | className = cl.getName, 11 | id = id.id, 12 | pk = "", 13 | metaList = NameMetaAttr(s"${id.id}") :: values.toList 14 | ) 15 | } 16 | 17 | case class WithPKMetaAttr(pk: String) extends AbstractMetaAttr 18 | 19 | case class SessionAttr[+By]( 20 | className: String, id: Long, pk: SrcId, metaList: List[AbstractMetaAttr] 21 | ){ 22 | def withPK(nPK: SrcId): SessionAttr[By] = copy(pk=nPK, metaList= WithPKMetaAttr(nPK) :: metaList) 23 | def addMeta( 24 | meta: AbstractMetaAttr*, 25 | ): SessionAttr[By] = copy(metaList = meta.toList ::: metaList) 26 | } 27 | 28 | trait SessionAttrAccessFactory { 29 | def to[P <: Product](attr: SessionAttr[P]): Context => Access[P] 30 | } 31 | 32 | trait RawSessionAttrUtils { 33 | def getAttrValue(sessionKey: String, pk: SrcId, attrId: Long, local: Context): Option[Product] 34 | def setAttrValue[P <: Product](sessionKey: String, pk: SrcId, attrId: Long, value: Option[P]): Seq[LEvent[Product]] 35 | } 36 | 37 | case object CurrentSessionKey extends TransientLens[SrcId]("") 38 | -------------------------------------------------------------------------------- /generator/src/main/scala/ee/cone/c4generator/ValInNonFinalGenerator.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4generator 2 | 3 | import scala.meta._ 4 | 5 | object ValInNonFinalGenerator extends Generator { 6 | def get(parseContext: ParseContext): List[Generated] = 7 | parseContext.stats.flatMap{ stat => 8 | stat.collect{ 9 | case q"..$mods class $tname[..$tparams] ..$ctorMods (...$paramss) extends $template" 10 | if mods.collect{ case mod"final" => true }.isEmpty => 11 | (tname,template) 12 | case q"..$mods trait $tname[..$tparams] extends $template" => 13 | (tname,template) 14 | }.flatMap{ 15 | case (tName,template"{ ..$statsA } with ..$inits { $self => ..$statsB }") => 16 | if(statsA.nonEmpty) println(s"warn: early initializer in $tName") 17 | statsB.collect{ 18 | case q"..$mods val ..$patsnel: $tpeopt = $expr" 19 | if mods.collect{ case mod"lazy" => true }.isEmpty => 20 | val valN = patsnel match { 21 | case Seq(Pat.Var(Term.Name(n))) => n 22 | case Seq(a: Tree) => throw new Exception(a.structure) 23 | } 24 | GeneratedCode(s"\nclass ${tName}_$valN(nonFinal: $tName) extends UnsafeValInNonFinalWarning(nonFinal.$valN)") 25 | } 26 | case _ => Nil 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4vdom/PathCommandApi.scala: -------------------------------------------------------------------------------- 1 | /*package ee.cone.c4vdom 2 | 3 | import ee.cone.c4vdom.Types.VDomKey 4 | 5 | t rait PathFactory { 6 | def path(key: VDomKey, children: ChildPair[OfPath]*): ChildPair[OfPathParent] 7 | def path(key: VDomKey, children: List[ChildPair[OfPath]]): ChildPair[OfPathParent] 8 | // 9 | def M(x:BigDecimal, y:BigDecimal): ChildPair[OfPath] 10 | def L(x:BigDecimal, y:BigDecimal): ChildPair[OfPath] 11 | def m(x:BigDecimal, y:BigDecimal): ChildPair[OfPath] 12 | def l(x:BigDecimal, y:BigDecimal): ChildPair[OfPath] 13 | def v(y:BigDecimal): ChildPair[OfPath] 14 | def h(x:BigDecimal): ChildPair[OfPath] 15 | def z: ChildPair[OfPath] 16 | def rect(a: Any*): ChildPair[OfPath] 17 | def ellipse( 18 | x: BigDecimal, y: BigDecimal, rx: BigDecimal, ry: BigDecimal, rotate: BigDecimal, 19 | startAngle: BigDecimal, endAngle: BigDecimal, counterclockwise: Boolean 20 | ): ChildPair[OfPath] 21 | def text(value: String, x: BigDecimal, y: BigDecimal) //textEx? 22 | // 23 | def transform( 24 | scaleX: BigDecimal, shearY: BigDecimal, 25 | shearX: BigDecimal, scaleY: BigDecimal, 26 | translateX: BigDecimal, translateY: BigDecimal 27 | ): ChildPair[OfPath] 28 | def translate(x: BigDecimal, y: BigDecimal): ChildPair[OfPath] 29 | def rotate(v: BigDecimal): ChildPair[OfPath] 30 | }*/ 31 | -------------------------------------------------------------------------------- /ci_up.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 -u 2 | import sys 3 | import subprocess 4 | from json import dumps, load, loads 5 | 6 | def log(text): print(text, file=sys.stderr) 7 | 8 | def debug_args(hint, args): 9 | log(f"{hint}: {' '.join(str(a) for a in args)}") 10 | return args 11 | 12 | def run(args, **opt): return subprocess.run(debug_args("running", args), check=True, **opt) 13 | 14 | def run_text_out(args, **opt): 15 | return subprocess.run(debug_args("running", args), check=True, text=True, capture_output=True, **opt).stdout 16 | 17 | sys.stdin.reconfigure(encoding='utf-8') 18 | info = load(sys.stdin) 19 | context, c4env, manifests = info["kube-context"], info["c4env"], info["manifests"] # info["state"] ignored 20 | kc = ("kubectl", "--context", context) 21 | env_filter = ("-l", f"c4env={c4env}") 22 | ingress_items = loads(run_text_out((*kc, "get", "ingress", "-o", "json", *env_filter)))["items"] 23 | ingress_types = sorted({f'{m["apiVersion"]}/Ingress' for m in ingress_items}) 24 | types = ("/v1/Service", "apps/v1/Deployment", "apps/v1/StatefulSet", *ingress_types) 25 | prune_list = [f"--prune-whitelist={v}" for v in types] 26 | manifests_str = "\n".join(dumps(v) for v in manifests) 27 | run((*kc, "apply", "--prune", *prune_list, *env_filter, "-f-"), text=True, input=manifests_str) 28 | log("** Deployment was applied to cluster. Use other tools to see further progress **") 29 | -------------------------------------------------------------------------------- /base_server/src/main/scala/ee/cone/c4gate_server/PublisherImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate_server 2 | 3 | import java.time.Instant 4 | import com.typesafe.scalalogging.LazyLogging 5 | import ee.cone.c4actor.Types.{SrcId, TxEvents} 6 | import ee.cone.c4actor._ 7 | import ee.cone.c4di.c4 8 | import ee.cone.c4gate.PurgePublication 9 | import ee.cone.c4gate.HttpProtocol.{S_HttpPublicationV1, S_HttpPublicationV2, S_Manifest} 10 | 11 | @c4("AbstractHttpGatewayApp") final case class PublicationPurgerTx(srcId: SrcId = "PublicationPurgerTx")( 12 | getS_Manifest: GetByPK[S_Manifest], getS_HttpPublicationV1: GetByPK[S_HttpPublicationV1], 13 | getS_HttpPublicationV2: GetByPK[S_HttpPublicationV2], getPurgePublication: GetByPK[PurgePublication], sleep: Sleep, 14 | ) extends SingleTxTr with LazyLogging { 15 | def transform(local: Context): TxEvents = { 16 | val now = System.currentTimeMillis 17 | val outdatedManifests = getS_Manifest.ofA(local).values.filter(_.until 17 | FinallyClose(new GzipSink(sink))( 18 | gzipSink => 19 | gzipSink.write(new Buffer().write(body), body.length) 20 | ) 21 | sink.readByteArray() 22 | } 23 | } 24 | 25 | 26 | class GzipStreamCompressor( 27 | readSink: Buffer = new Buffer() 28 | )( 29 | gzipSink: GzipSink = new GzipSink(readSink) 30 | ) extends RawCompressor { 31 | def name: String = "gzip" 32 | 33 | def compress(body: Array[Byte]): Array[Byte] = synchronized { 34 | gzipSink.write(new Buffer().write(body), body.length) 35 | gzipSink.flush() 36 | readSink.readByteArray() 37 | } 38 | 39 | // need? def close():Unit = gzipSink.close() 40 | } 41 | 42 | class GzipStreamCompressorFactory extends StreamCompressorFactory { 43 | def create(): Option[RawCompressor] = Option(new GzipStreamCompressor()()) 44 | } -------------------------------------------------------------------------------- /micro/dig/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl / 3 | RUN /install.pl useradd 1979 4 | RUN /install.pl apt curl ca-certificates unzip 5 | RUN /install.pl curl https://download.bell-sw.com/java/25.0.1+13/bellsoft-jdk25.0.1+13-linux-amd64.tar.gz 6 | RUN /install.pl curl https://dl.k8s.io/release/v1.33.1/bin/linux/amd64/kubectl && chmod +x /tools/kubectl 7 | RUN curl -L https://github.com/com-lihaoyi/Ammonite/releases/download/3.0.4/3.3-3.0.4 -o /tmp/amm \ 8 | && echo "#!/usr/bin/env sh" > /tools/amm && cat /tmp/amm >> /tools/amm && chmod +x /tools/amm && chown c4:c4 /tools/amm \ 9 | && rm /tmp/amm 10 | USER c4 11 | RUN curl -L https://github.com/async-profiler/async-profiler/releases/download/v4.1/async-profiler-4.1-linux-x64.tar.gz -o /c4/profiler.tar.gz 12 | RUN curl -L https://github.com/alibaba/arthas/releases/download/arthas-all-4.1.1/arthas-bin.zip -o /c4/arthas-bin.zip 13 | RUN mkdir -p /tmp/c4dig/arthas \ 14 | && cd /tmp/c4dig && tar xzf /c4/profiler.tar.gz && mv async-profiler-4.1-linux-x64 async \ 15 | && mkdir async_out \ 16 | && cd /tmp/c4dig/arthas && unzip /c4/arthas-bin.zip \ 17 | && cd /tmp && tar -C /tmp -czf /c4/c4dig.tar.gz c4dig \ 18 | && rm -r /tmp/c4dig 19 | ENV PATH=${PATH}:/tools/:/tools/jdk/bin 20 | ENTRYPOINT ["perl","-e","-e and exec 'amm', $_ for map{$_.'/app.scala'} split ':', $ENV{C4UP_PATH}; die"] 21 | #todo: using compilation image can save some memory and boot time -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4gate/HiRateTxApp.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor.Types.SrcId 5 | import ee.cone.c4actor._ 6 | import ee.cone.c4actor.QProtocol.S_Firstborn 7 | import ee.cone.c4assemble.Types.{Each, Values} 8 | import ee.cone.c4assemble._ 9 | import ee.cone.c4di.c4multi 10 | import ee.cone.c4proto.ToByteString 11 | 12 | @c4("HiRateTxApp") final case class HiRateTx(srcId: SrcId = "HiRateTx")( 13 | publisher: Publisher, 14 | ) extends SingleTxTr with LazyLogging { 15 | def transform(local: Context): TxEvents = { 16 | val timeStr = System.currentTimeMillis.toString 17 | logger.info(s"start handling $timeStr") 18 | val bytes = ToByteString(timeStr) 19 | publisher.publish(ByPathHttpPublication("/time",Nil,bytes),_+1000*60) 20 | } 21 | } 22 | 23 | /* 24 | @assemble class HiRateAssemble { 25 | def joinPosts( 26 | key: SrcId, 27 | post: Each[HttpPost] 28 | ): Values[(SrcId, TxTransform)] = 29 | List(WithPK(TestDelayHttpPostHandler(post.srcId, post))) 30 | } 31 | 32 | case class HiRateTx(srcId: SrcId, post: HttpPost) extends TxTransform with LazyLogging { 33 | def transform(local: Context): Context = { 34 | logger.info(s"start handling $srcId") 35 | concurrent.blocking{ 36 | Thread.sleep(1000) 37 | } 38 | logger.info(s"finish handling $srcId") 39 | txAdd.add(delete(post))(local) 40 | } 41 | }*/ 42 | -------------------------------------------------------------------------------- /client/src/main/location.ts: -------------------------------------------------------------------------------- 1 | 2 | import {useEffect} from "./react" 3 | import {Identity, manageEventListener, identityAt, mergeSimple, patchFromValue, UseSync} from "./util" 4 | 5 | const changeIdOf = identityAt('change') 6 | type LocationBranchContext = { isRoot: boolean, win: Window } 7 | export const LocationComponents = ({useBranch,useSync}: {useBranch: ()=>LocationBranchContext, useSync: UseSync}) => { 8 | const LocationElement = ({value: incomingValue, identity}: {value: string, identity: Identity}) => { 9 | const {isRoot,win} = useBranch() 10 | //console.log("loc",incomingValue) 11 | const [patches, enqueuePatch] = useSync(changeIdOf(identity)) 12 | const value = mergeSimple(incomingValue, patches) 13 | const rootWin = isRoot ? win : undefined 14 | const location = rootWin?.location 15 | useEffect(()=>{ 16 | if(location) enqueuePatch(patchFromValue(location.href)) 17 | }, [location, enqueuePatch]) 18 | useEffect(()=>{ 19 | if(location && value && location.href !== value) location.href = value //? = "#"+data 20 | }, [location, value, enqueuePatch]) 21 | useEffect(() => { 22 | return !rootWin ? undefined : 23 | manageEventListener(rootWin, "hashchange", ev => enqueuePatch(patchFromValue(ev.newURL))) 24 | }, [rootWin, enqueuePatch]) 25 | return [] 26 | } 27 | return {LocationElement} 28 | } -------------------------------------------------------------------------------- /micro/s3client/main.py: -------------------------------------------------------------------------------- 1 | 2 | from subprocess import check_call 3 | from pathlib import Path 4 | from os import environ 5 | from socket import create_connection 6 | from sys import argv 7 | 8 | def one(it): return it 9 | 10 | def never(a): raise Exception(a) 11 | 12 | def read_conf(key): return (Path(environ["C4S3_CONF_DIR"]) / key).read_bytes().decode() 13 | 14 | def kafka_port(): return 9000 15 | 16 | def serve(_): 17 | check_call(("/tools/mc", "alias", "set", "def", read_conf("address"), read_conf("key"), read_conf("secret"))) 18 | cp = Path("/c4/kafka-clients-classpath").read_bytes().decode().strip() 19 | check_call(("java", "--source", "21", "--enable-preview", "-cp", cp, "/app/kafka.java", str(kafka_port()))) 20 | 21 | def sock_exchange_init(sock): 22 | file = sock.makefile('r', encoding='utf-8', newline='\n') 23 | def exchange(msg: bytes, need_resp: str): 24 | sock.sendall(msg + b'\n') 25 | resp_tp, *resp_args = file.readline().split() 26 | return resp_args if resp_tp == need_resp else never(f"bad resp: {resp_tp} {resp_args}") 27 | return exchange 28 | 29 | def produce_one(topic, message): 30 | with create_connection(("127.0.0.1",kafka_port())) as sock: 31 | exchange = sock_exchange_init(sock) 32 | exchange(f'PRODUCE {topic}'.encode(), "OK") 33 | print(one(*exchange(message.encode(), "ACK"))) 34 | 35 | { "serve": serve, "produce_one": produce_one }[argv[1]](*argv[2:]) 36 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ElectorApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4proto.{Id, protocol} 5 | 6 | import java.time.Instant 7 | 8 | trait CurrentProcess { 9 | def id: SrcId 10 | } 11 | 12 | trait ReadyProcesses extends Product { 13 | def all: List[ReadyProcess] 14 | def enabledForCurrentRole: List[SrcId] 15 | } 16 | 17 | trait ReadyProcess extends Product { 18 | def id: SrcId 19 | def txId: String 20 | def role: String 21 | def startedAt: Long 22 | def hostname: String 23 | def refDescr: String 24 | def completionReqAt: Option[Instant] 25 | def complete(at: Instant): Seq[LEvent[Product]] 26 | 27 | // `halt` removes replica in inconsistent way, ignoring elector, so: 28 | // other replicas will think, that it does not exist, although it can run with tx-s yet; 29 | // removed replica will halt as soon as possible, even without completing cleanup hooks. 30 | def halt: Seq[LEvent[Product]] 31 | } 32 | 33 | case class EnabledTxTr(value: TxTransform) 34 | 35 | trait ReadyProcessUtil { 36 | def getAll(local: AssembledContext): ReadyProcesses 37 | def getCurrent(local: AssembledContext): ReadyProcess 38 | } 39 | 40 | case class DisableTxTr(srcId: SrcId) 41 | 42 | case class BeforeInjection(srcId: SrcId) 43 | abstract class GeneralBeforeInjectionTxTrCl(val cl: Class[_]) 44 | abstract class BeforeInjectionTxTrCl[T<:TxTransform](cl: Class[T]) extends GeneralBeforeInjectionTxTrCl(cl) 45 | -------------------------------------------------------------------------------- /client/src/main/frames.ts: -------------------------------------------------------------------------------- 1 | 2 | import {createRoot,Root} from "react-dom/client" 3 | import {useState,useEffect} from "./react" 4 | 5 | const FRAME_SRC = "/blank.html" 6 | 7 | export const useIsolatedFrame = (makeChildren: (body: HTMLElement)=>React.ReactNode) => { 8 | const [frameElement,setFrameElement] = useState(null) 9 | const [root,setRoot] = useState(null) 10 | const theBody = frameElement?.contentWindow?.document.body || null 11 | useEffect(() => { 12 | if(!theBody) return 13 | const [root, unmount] = doCreateRoot(theBody) 14 | setRoot(root) 15 | return () => { setTimeout(() => unmount()) } // avoid unmounting during render 16 | }, [theBody]) 17 | useEffect(() => theBody ? root?.render(makeChildren(theBody)) : undefined, [theBody,root,makeChildren]) 18 | const onLoad = (e: React.SyntheticEvent) => setFrameElement(e.currentTarget) 19 | return {src: FRAME_SRC, onLoad} 20 | } 21 | export const doCreateRoot = (parentNativeElement: HTMLElement): [Root,()=>void] => { //, children: React.ReactNode; root.render(children) 22 | const rootNativeElement = parentNativeElement.ownerDocument.createElement("span") 23 | parentNativeElement.appendChild(rootNativeElement) 24 | const root = createRoot(rootNativeElement) 25 | return [root, () => { 26 | root.unmount() 27 | rootNativeElement.parentElement?.removeChild(rootNativeElement) 28 | }] 29 | } 30 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4gate/LongHungry.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor.QProtocol.S_Firstborn 5 | import ee.cone.c4actor._ 6 | import ee.cone.c4actor.Types.SrcId 7 | import ee.cone.c4assemble.Types.{Each, Values} 8 | import ee.cone.c4assemble.c4assemble 9 | import ee.cone.c4di.c4multi 10 | import ee.cone.c4gate.HttpProtocol.N_Header 11 | import ee.cone.c4gate.{ByPathHttpPublication, Publisher} 12 | import ee.cone.c4gate.LongHungryProto.D_Blob 13 | import ee.cone.c4proto._ 14 | import okio.ByteString 15 | 16 | import java.time.Instant 17 | 18 | @protocol("LongHungryApp") object LongHungryProto { 19 | @Id(0x6a98) case class D_Blob(@Id(0x6a99) srcId: SrcId, @Id(0x6a9a) data: ByteString) 20 | } 21 | 22 | @c4("LongHungryApp") final case class LongHungryLongTx(srcId: SrcId = "LongHungryLongTx") 23 | extends SingleTxTr with LazyLogging 24 | { 25 | def transform(local: Context): TxEvents = { 26 | for(i <- LazyList.from(0)){ 27 | logger.info("more long") 28 | Thread.sleep(1000) 29 | } 30 | Nil 31 | } 32 | } 33 | 34 | @c4("LongHungryApp") final case class LongHungryHungryTx(srcId: SrcId = "LongHungryHungryTx")( 35 | sleep: Sleep, 36 | ) extends SingleTxTr with LazyLogging { 37 | def transform(local: Context): TxEvents = { 38 | logger.info("more hungry") 39 | LEvent.update(D_Blob("LongHungry", ToByteString(Instant.now.toString * 1000000))) ++ sleep.forSeconds(1) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /c4util/kube_reporter.py: -------------------------------------------------------------------------------- 1 | 2 | def single(items, get_default): return items[0] if len(items) == 1 else get_default() 3 | 4 | 5 | def item_to_str(it): 6 | name = it.get("metadata", {}).get("name") 7 | if not name: 8 | return None 9 | spec = it.get("spec", {}) 10 | node = "-".join(spec.get("nodeName", "").split("-")[:2]) 11 | requests = single(spec.get("containers", []), lambda: {}).get("resources", {}).get("requests", {}) 12 | req_str = "/".join(v for v in (requests.get("cpu", ""), requests.get("memory", "")) if v) 13 | container_status = single(it.get("status", {}).get("containerStatuses", []), lambda: {}) 14 | image_pf = container_status.get("image", "").split(":")[-1] 15 | ready = container_status.get("ready") 16 | restart_count = str(container_status.get("restartCount", "")) 17 | started_at = container_status.get("state", {}).get("running", {}).get("startedAt", "") 18 | return name, image_pf, node, restart_count, started_at, "Y" if ready else "", req_str 19 | 20 | 21 | def get_cluster_report(items): 22 | head = ("NAME", "TAG", "NODE", "RESTARTS", "STARTED", "READY", "REQ") 23 | right = {"RESTARTS", "REQ"} 24 | rows = [head] + sorted(it for it in [item_to_str(it) for it in items] if it) 25 | widths = [max(len(str(row[cn])) for row in rows) for cn in range(len(head))] 26 | return "\n".join(" ".join( 27 | (row[cn].rjust if head[cn] in right else row[cn].ljust)(widths[cn], " ") 28 | for cn in range(len(head)) 29 | ) for row in rows) 30 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/DebugRawWorld.scala: -------------------------------------------------------------------------------- 1 | /*package ee.cone.c4actor 2 | 3 | import java.nio.charset.StandardCharsets.UTF_8 4 | 5 | import ee.cone.c4actor.QProtocol.S_Updates 6 | import ee.cone.c4actor.Types.{NextOffset, SharedComponentMap} 7 | import ee.cone.c4proto.ToByteString 8 | */ 9 | /* 10 | object DebugInit extends ToInject { 11 | def toInject: List[Injectable] = DebugKey.set(None) 12 | }*/ 13 | 14 | /* 15 | class DebugRichRawWorldFactory(rawSnapshot: RawSnapshot, options: RawDebugOptions, inner: RawWorldFactory) extends RawWorldFactory{ 16 | def create(): RawWorld = rawSnapshot.loadRecent(inner.create(), None) match { 17 | case world: RichContext => 18 | val data = options.load("request-event") 19 | if(data.isEmpty) world else { 20 | val event = RawEvent(world.offset, ToByteString(data)) 21 | val injectMore = DebugKey.set(Option((world.assembled,event))) 22 | new DebugRichRawWorld(world, world.injected ++ injectMore.map(_.pair)) 23 | } 24 | } 25 | } 26 | class DebugRichRawWorld( 27 | inner: RawWorld with RichContext, 28 | val injected: SharedComponentMap 29 | ) extends RawWorld with RichContext { 30 | def assembled: ReadModel = inner.assembled 31 | def offset: NextOffset = inner.offset 32 | def reduce(events: List[RawEvent]): RawWorld = 33 | new DebugRichRawWorld(inner.reduce(events) match{ case w: RawWorld with RichContext => w }, injected) 34 | def hasErrors: Boolean = inner.hasErrors 35 | def save(): String = inner.save() 36 | } 37 | */ -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_xml/S3ListerImpl.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4actor_xml 3 | 4 | import com.typesafe.scalalogging.LazyLogging 5 | import ee.cone.c4actor.{S3Lister, S3Manager, TxLogName} 6 | import ee.cone.c4di.c4 7 | 8 | import java.nio.charset.StandardCharsets.UTF_8 9 | import java.time.ZonedDateTime 10 | import scala.concurrent.{ExecutionContext, Future} 11 | import scala.xml.XML 12 | 13 | @c4("S3ListerApp") final class S3ListerImpl(s3: S3Manager) extends S3Lister with LazyLogging { 14 | def list(txLogName: TxLogName, resource: String)(implicit ec: ExecutionContext): Future[Option[List[(String,String)]]] = { 15 | def iter(addSearch: String, was: List[List[(String,String)]]): Future[Option[List[(String,String)]]] = 16 | s3.get(s3.join(txLogName,s"$resource?list-type=2$addSearch"))(ec).flatMap( 17 | _.fold(Future.successful(None:Option[List[(String,String)]])){ data => 18 | val content = new String(data, UTF_8) 19 | val xml = XML.loadString(content) 20 | logger.debug(s"$xml") 21 | val will = 22 | (for(item <- xml \ "Contents") yield ((item \ "Key").text, (item \ "LastModified").text)).toList :: was 23 | val token: String = (xml \ "NextContinuationToken").text 24 | if(token.isEmpty) Future.successful(Option(will.reverse.flatten)) else iter(s"&continuation-token=$token", will) 25 | } 26 | ) 27 | iter("", Nil) 28 | } 29 | def parseTime(s: String): Long = ZonedDateTime.parse(s).toInstant.toEpochMilli 30 | } 31 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4ui/SortImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor.Context 4 | import ee.cone.c4di.{c4, provide} 5 | import ee.cone.c4vdom.Types._ 6 | import ee.cone.c4vdom._ 7 | import ee.cone.c4vdom.Types.VDomKey 8 | 9 | //@c4tags("UICompApp") trait InnerSortTags[C] { 10 | // @c4tag("TBodySortRoot") def tBodyRoot(key: String, sort: Receiver[C], children: List[VDom[OfDiv]]): VDom[OfDiv] 11 | // @c4tag("SortHandle") def handle(key: String, item: VDom[OfDiv]): VDom[OfDiv] 12 | //} 13 | 14 | //@c4("UICompApp") final class SortTagsImpl( 15 | // innerProvider: InnerSortTagsProvider, 16 | // sortReceiverFactory: SortReceiverFactory, 17 | //)( 18 | // inner: InnerSortTags[Context] = innerProvider.get[Context] 19 | //) extends SortTags { 20 | // def tBodyRoot(handler: SortHandler)(items: ChildPair[OfDiv]*): ChildPair[OfDiv] = 21 | // inner.tBodyRoot("body", sortReceiverFactory.create(handler), items.toList) 22 | // def handle(key: VDomKey, item: ChildPair[OfDiv]): ChildPair[OfDiv] = inner.handle(key,item) 23 | //} 24 | 25 | @c4("UICompApp") final class SortReceiverFactoryImpl extends SortReceiverFactory { 26 | def create(handler: SortHandler): Receiver[Context] = 27 | SortReceiverImpl(handler) 28 | } 29 | 30 | case class SortReceiverImpl(handler: SortHandler) extends Receiver[Context] { 31 | def receive: Handler = message => 32 | handler.handle( 33 | message.header("x-r-sort-obj-key"), 34 | (message.header("x-r-sort-order-0"), message.header("x-r-sort-order-1")), 35 | ) 36 | } 37 | -------------------------------------------------------------------------------- /c4util/s3sign.java: -------------------------------------------------------------------------------- 1 | 2 | import java.nio.file.*; 3 | import java.nio.charset.StandardCharsets; 4 | import javax.crypto.Mac; 5 | import javax.crypto.spec.SecretKeySpec; 6 | import java.time.format.DateTimeFormatter; 7 | import java.time.*; 8 | import java.util.*; 9 | 10 | String mandatoryEnv(String key) throws Exception { 11 | final var v = System.getenv(key); 12 | if(v == null || v.length() == 0) throw new Exception("no "+key); 13 | return v; 14 | } 15 | 16 | void main(String[] args){ 17 | try{ 18 | final var confDir = Paths.get(mandatoryEnv("C4S3_CONF_DIR")); 19 | final var key = Files.readString(confDir.resolve("key")); 20 | final var secret = Files.readAllBytes(confDir.resolve("secret")); 21 | final var date = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz",Locale.ENGLISH) 22 | .withZone(ZoneId.of("GMT")).format(Instant.now()); 23 | final var canonicalIn = args[0].replace("[date]", date); 24 | final var algorithm = "HmacSHA1"; 25 | final var mac = Mac.getInstance(algorithm); 26 | final var UTF_8 = StandardCharsets.UTF_8; 27 | mac.init(new SecretKeySpec(secret, algorithm)); 28 | final var signature = new String(Base64.getEncoder().encode(mac.doFinal(canonicalIn.getBytes(UTF_8))),UTF_8); 29 | System.out.println(STR."Date:\{date}"); 30 | System.out.println(STR."Authorization:AWS \{key}:\{signature}"); 31 | } catch(Exception e){ 32 | e.printStackTrace(); 33 | System.exit(1); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/hashsearch/index/dynamic/IndexNodeProtocol.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.hashsearch.index.dynamic 2 | 3 | import ee.cone.c4proto._ 4 | 5 | @protocol("DynamicIndexAssemble") object IndexNodeProtocol { 6 | @Id(0x205) case class S_IndexNodesVersion( 7 | @Id(0x207) srcId: String, 8 | @Id(0x206) version: String 9 | ) 10 | 11 | // A 12 | @GenLens 13 | @Id(0x0169) case class S_IndexNode( 14 | @Id(0x016a) indexNodeId: String, 15 | @Id(0x016b) modelId: Int, 16 | @Id(0x016c) byAdapterId: Long, 17 | @Id(0x0187) commonPrefix: String 18 | ) 19 | 20 | // B 21 | @Id(0x0180) case class S_IndexNodeSettings( 22 | @Id(0x0181) srcId: String, 23 | @Id(0x0182) allAlwaysAlive: Boolean, 24 | @Id(0x0195) keepAliveSeconds: Option[Long] 25 | ) 26 | 27 | // C 28 | @GenLens 29 | @Id(0x0170) case class S_IndexByNode( 30 | @Id(0x0175) leafId: String, 31 | @Id(0x0177) indexNodeId: String, 32 | @Id(0x0194) modelId: Int, 33 | @Id(0x0173) heapIds: List[String], 34 | @Id(0x0204) byStr: String 35 | ) 36 | 37 | @Id(0x0201) case class S_IndexByNodeLastSeen( 38 | @Id(0x0202) srcId: String, 39 | @Id(0x0203) lastSeenAtSeconds: Long 40 | ) 41 | 42 | // E 43 | @Id(0x0190) case class S_IndexByNodeSettings( 44 | @Id(0x0191) srcId: String, 45 | @Id(0x0192) alwaysAlive: Boolean, 46 | @Id(0x0193) keepAliveSeconds: Option[Long] 47 | ) 48 | 49 | @Id(0x0196) case class S_TimeMeasurement( 50 | @Id(0x0197) srcId: String, 51 | @Id(0x0198) measurement: Option[Long] 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate_devel/DevelMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate_devel 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4actor_kafka_impl.{KafkaConsumerApp, LZ4DeCompressorApp, LZ4RawCompressorApp} 5 | import ee.cone.c4actor_logback_impl.BasicLoggingApp 6 | import ee.cone.c4actor_xml.S3ListerApp 7 | import ee.cone.c4di.c4app 8 | import ee.cone.c4gate.DevConfigApp 9 | import ee.cone.c4gate.DisableDefaultSafeToRunApp 10 | 11 | //@c4app class TopicToDirAppBase extends VMExecutionApp with ExecutableApp with BaseApp with ProtoApp 12 | // with KafkaConsumerApp with SnapshotUtilImplApp with EnvConfigCompApp 13 | // with BasicLoggingApp with CatchNonFatalApp with SnapshotSaverApp 14 | 15 | @c4app class TopicToS3AppBase extends VMExecutionApp with ExecutableApp with BaseApp with ProtoApp 16 | with KafkaConsumerApp with SnapshotUtilImplApp with EnvConfigCompApp 17 | with BasicLoggingApp with CatchNonFatalApp with S3ListerApp with TxGroupApp 18 | 19 | trait FileConsumerAppBase 20 | trait WorldCheckerAppBase 21 | trait TxGroupAppBase 22 | trait ExtractTxAppBase extends TxGroupApp 23 | trait ReplayApp extends FileConsumerApp with WorldCheckerApp with DisableDefaultS3RawSnapshotApp 24 | with ExtractTxApp with SnapshotUtilImplApp with DisableDefaultSafeToRunApp 25 | 26 | @c4app class OrigStatReplayAppBase extends VMExecutionApp with ExecutableApp with BaseApp with ProtoApp 27 | with FileConsumerApp with SnapshotUtilImplApp with EnvConfigCompApp with DevConfigApp 28 | with ExtractTxApp with SnapshotLoaderImplApp with LZ4RawCompressorApp with LZ4DeCompressorApp 29 | with BasicLoggingApp with CatchNonFatalApp -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/tests/ScalametaTest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.tests 2 | 3 | import scala.collection.immutable.Seq 4 | import scala.meta.Term.Name 5 | import scala.meta._ 6 | 7 | object ScalametaTest { 8 | def main(args: Array[String]): Unit = { 9 | val s = "override val test: List[Int] = 1 ::: super.test".parse[Stat].get 10 | 11 | def parseType(t: Type): String = { 12 | t match { 13 | case t"$tpe[..$tpesnel]" => s"""ee.cone.c4proto.TypeProp(classOf[$tpe[${tpesnel.map(_ => "_").mkString(", ")}]].getName, "$tpe", ${tpesnel.map(parseType)})""" 14 | case t"$tpe" => s"""ee.cone.c4proto.TypeProp(classOf[$tpe].getName, "$tpe", Nil)""" 15 | } 16 | } 17 | //println(parseType(s)) 18 | //println(s) 19 | println(s match { 20 | case q"override val ..$vname: $tpe = $expr" => 21 | expr.collect({ 22 | case q"super.test" => 1 23 | case _ => 0 24 | }) 25 | case _ => 666 :: Nil 26 | }) 27 | 28 | val defenition = "@ignore def test(arg: Int): LUL = {val a = 3}".parse[Stat].get 29 | defenition match { 30 | case q"@ignore def $ename[..$tparams](...$paramss): $tpeopt = $expr" => println("def ok") 31 | case _ => println("not ok") 32 | } 33 | 34 | def parseArgs: Seq[Seq[Term]] => List[String] = 35 | _.flatMap(_.map(_.toString())).toList 36 | 37 | val text = "@Meta(Atata, ee.cone.ee.Totoot(1,1,1)) val a = 1".parse[Stat].get 38 | text match { 39 | case q"@Meta(...$exprss) val a = 1" => println(parseArgs(exprss)) 40 | case _ => () 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/IdGenUtilImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import java.nio.ByteBuffer 4 | import java.nio.charset.StandardCharsets.UTF_8 5 | import java.security.MessageDigest 6 | import java.util.{Base64, UUID} 7 | import ee.cone.c4actor.Types.SrcId 8 | import ee.cone.c4assemble.Interner 9 | import ee.cone.c4di.c4 10 | import okio.ByteString 11 | 12 | import scala.collection.immutable.TreeMap 13 | 14 | @c4("RichDataCompApp") final case class IdGenUtilImpl( 15 | proto: MessageDigest = MessageDigest.getInstance("MD5") 16 | ) extends IdGenUtil { 17 | private def md5(data: Array[Byte]*): String = { 18 | val d = proto.clone().asInstanceOf[MessageDigest] // much faster than getInstance("MD5") 19 | data.foreach{ bytes => 20 | val l = bytes.length 21 | d.update((l>>24).toByte) 22 | d.update((l>>16).toByte) 23 | d.update((l>> 8).toByte) 24 | d.update((l>> 0).toByte) 25 | d.update(bytes) 26 | } 27 | Interner.intern(Base64.getUrlEncoder.encodeToString(d.digest)) 28 | } 29 | private def toBytes(value: String): Array[Byte] = value.getBytes(UTF_8) 30 | private def toBytes(value: Long): Array[Byte] = 31 | ByteBuffer.allocate(java.lang.Long.BYTES).putLong(value).array() 32 | 33 | def srcIdFromSrcIds(srcIdList: SrcId*): SrcId = md5(srcIdList.map(toBytes):_*) 34 | def srcIdFromStrings(stringList: String*): SrcId = md5(stringList.map(toBytes):_*) 35 | def srcIdFromSerialized(adapterId: Long, bytes: ByteString): SrcId = 36 | md5(toBytes(adapterId),bytes.toByteArray) 37 | def srcIdRandom(): SrcId = srcIdFromStrings(UUID.randomUUID.toString) 38 | } 39 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4vdom_impl/VDomDiff.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4vdom_impl 2 | 3 | import ee.cone.c4vdom.VDomValue 4 | 5 | import scala.annotation.tailrec 6 | 7 | case class DoSetPair(value: VDomValue) extends VPair { 8 | def jsonKey = "$set" 9 | def sameKey(other: VPair) = Never() 10 | def withValue(value: VDomValue) = Never() 11 | } 12 | 13 | class DiffImpl(createMapValue: List[VPair]=>MapVDomValue, wasNoValue: WasNoVDomValue) extends Diff { 14 | private def set(value: VDomValue) = Some(createMapValue(DoSetPair(value)::Nil)) 15 | def diff(prevValue: VDomValue, currValue: VDomValue): Option[MapVDomValue] = prevValue match { 16 | case p: MapVDomValue => currValue match { 17 | case n: MapVDomValue => 18 | @tailrec def iter(previous: List[VPair], current: List[VPair], res: List[VPair]): Option[MapVDomValue] = 19 | if(current.nonEmpty){ 20 | val nPrevious = 21 | if(previous.isEmpty || !current.head.sameKey(previous.head)) 22 | current.head.withValue(wasNoValue) :: previous 23 | else previous 24 | val d = diff(nPrevious.head.value, current.head.value) 25 | val nRes = if (d.nonEmpty) current.head.withValue(d.get) :: res else res 26 | iter(nPrevious.tail, current.tail, nRes) 27 | } 28 | else if(previous.nonEmpty) set(n) 29 | else if(res.nonEmpty) Some(createMapValue(res)) 30 | else None 31 | iter(p.pairs, n.pairs, Nil) 32 | case n => set(currValue) 33 | } 34 | case p if p == currValue => None 35 | case p => set(currValue) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4gate/SignedReqUtilImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate 2 | 3 | import ee.cone.c4actor.Types.LEvents 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4gate.HttpProtocol._ 6 | import ee.cone.c4gate.Time._ 7 | import ee.cone.c4di.c4 8 | import ee.cone.c4proto.ToByteString 9 | import okio.ByteString 10 | 11 | @c4("SignedReqUtilImplApp") final class SignedReqUtilImpl( 12 | val catchNonFatal: CatchNonFatal, 13 | publisher: Publisher, 14 | ) extends SignedReqUtil { 15 | def header(headers: List[N_Header], key: String): Option[String] = 16 | headers.find(_.key == key).map(_.value) 17 | def signed(headers: List[N_Header]): Option[String] = header(headers,"x-r-signed") 18 | def respond(succeeded: List[(S_HttpRequest, List[N_Header])], failed: List[(S_HttpRequest, String)]): LEvents = { 19 | val res = succeeded ++ failed.map{ case(req,msg) => req -> List(N_Header("x-r-error-message", msg)) } 20 | val updates = for { 21 | (post, headers) <- res 22 | key <- header(post.headers,"x-r-response-key").toList 23 | update <- publisher.publish(ByPathHttpPublication(s"/response/$key", headers, ByteString.EMPTY), _+hour) 24 | } yield update 25 | val deletes = for { 26 | (post, headers) <- res 27 | delete <- LEvent.delete(post) 28 | } yield delete 29 | val now = System.currentTimeMillis 30 | val respFailUpdates = for { 31 | (post, msg) <- failed 32 | update <- LEvent.update(S_HttpResponse( 33 | post.srcId, 500, N_Header("Content-Type", "text/html; charset=UTF-8") :: Nil, ToByteString(msg), now 34 | )) 35 | } yield update 36 | updates ++ deletes ++ respFailUpdates 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4ui/UIExtraMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor._ 4 | import ee.cone.c4actor_branch.{BranchOperations, ToAlienSender} 5 | import ee.cone.c4di.c4 6 | import ee.cone.c4gate.ToAlienMessageUtil 7 | import ee.cone.c4gate_akka.AkkaGatewayApp 8 | import ee.cone.c4vdom.{ChildPairFactory, TagJsonUtils, VDomResolver} 9 | 10 | import scala.collection.immutable.Seq 11 | 12 | trait VDomApp extends ComponentProviderApp { 13 | lazy val childPairFactory: ChildPairFactory = resolveSingle(classOf[ChildPairFactory]) 14 | lazy val tagJsonUtils: TagJsonUtils = resolveSingle(classOf[TagJsonUtils]) 15 | lazy val vDomResolver: VDomResolver = resolveSingle(classOf[VDomResolver]) 16 | } 17 | 18 | trait ExtraUIApp extends UICompApp with VDomApp with AlienExchangeApp with AkkaGatewayApp { 19 | lazy val branchOperations: BranchOperations = resolveSingle(classOf[BranchOperations]) 20 | lazy val untilPolicy: UntilPolicy = resolveSingle(classOf[UntilPolicy]) 21 | } 22 | 23 | //// 24 | 25 | @deprecated trait AlienExchangeAppBase extends AlienExchangeCompApp 26 | @c4("AlienExchangeApp") final class SendToAlienInit( 27 | toAlienSender: ToAlienSender, 28 | ) extends ToInject { 29 | def toInject: List[Injectable] = SendToAlienKey.set(toAlienSender.send) 30 | } 31 | @deprecated @c4("AlienExchangeApp") final class ToAlienSenderImpl( 32 | toAlienMessageUtil: ToAlienMessageUtil, txAdd: LTxAdd 33 | ) extends ToAlienSender { 34 | def send(sessionKeys: Seq[String], evType: String, data: String): Context => Context = { 35 | val lEvents = for(k<-sessionKeys; ev<-toAlienMessageUtil.create(k, s"${evType}\n${data}")) yield ev 36 | txAdd.add(lEvents) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_branch/BranchApi.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4actor_branch 3 | 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4actor.Types.{LEvents, SrcId} 6 | import ee.cone.c4actor_branch.BranchTypes.{BranchKey, BranchResult} 7 | import ee.cone.c4proto._ 8 | 9 | object BranchTypes { 10 | type BranchKey = SrcId 11 | type BranchResult = BranchProtocol.N_BranchResult 12 | } 13 | 14 | trait BranchErrorSaver { 15 | def saveErrors(local: Context, branchKey: BranchKey, error: Throwable): Seq[LEvent[Product]] 16 | } 17 | 18 | trait BranchTask extends Product { 19 | def branchKey: SrcId 20 | def product: Product 21 | def relocate(to: String): Context => Context 22 | } 23 | 24 | trait BranchOperations { 25 | def toSeed(value: Product): BranchResult 26 | def collect[T<:Product](seeds: Seq[BranchResult], cl: Class[T]): Seq[T] 27 | def saveChanges(local: Context, branchKey: String, seeds: List[BranchResult]): LEvents 28 | def purge(local: Context, branchKey: String): LEvents 29 | } 30 | 31 | @protocol("BranchApp") object BranchProtocol { 32 | @Id(0x0040) case class S_BranchResults( 33 | @Id(0x0041) branchKey: String, 34 | @Id(0x0044) children: List[N_BranchResult], 35 | // was fields 0x0042 0x0043 0x0045 36 | ) 37 | case class N_BranchResult( 38 | @Id(0x0041) hash: String, 39 | @Id(0x0042) valueTypeId: Long, 40 | @Id(0x0043) value: okio.ByteString, 41 | ) 42 | 43 | @Id(0x004B) case class U_Redraw( 44 | @Id(0x004C) srcId: String, 45 | @Id(0x004D) branchKey: String 46 | ) 47 | 48 | @Id(0x004E) case class N_RestPeriod( 49 | @Id(0x004D) branchKey: String, 50 | @Id(0x004F) value: Long 51 | ) 52 | } 53 | 54 | trait BranchError { 55 | def message(local: Context): String 56 | } 57 | -------------------------------------------------------------------------------- /c4util/git.py: -------------------------------------------------------------------------------- 1 | 2 | from . import run, run_no_die, run_text_out, log, never_if 3 | 4 | 5 | def git_init(repo, d): 6 | run(("git", "init"), cwd=d) 7 | run(("git", "remote", "add", "origin", repo), cwd=d) 8 | 9 | 10 | def git_clone(repo, branch, d): 11 | run(("git", "clone", "--depth", "1", "-b", branch, "--", repo, d )) 12 | 13 | 14 | def git_pull(d): 15 | branch = run_text_out(("git", "branch", "--show-current"), cwd=d).strip() 16 | never_if(None if branch else "not a branch") 17 | run(("git", "pull", "origin", branch), cwd=d) 18 | 19 | 20 | def git_set_user(d): 21 | run(("git", "config", "user.email", "ci@c4proto"), cwd=d) 22 | run(("git", "config", "user.name", "ci@c4proto"), cwd=d) 23 | 24 | 25 | def git_add_tagged(d, tag): 26 | git_set_user(d) 27 | run(("git", "add", "."), cwd=d) 28 | run(("git", "commit", "-m-"), cwd=d) 29 | run(("git", "tag", tag), cwd=d) 30 | run_no_die(("git", "push", "--delete", "origin", tag), cwd=d) 31 | run(("git", "push", "--tags", "origin"), cwd=d) 32 | 33 | 34 | def git_clone_or_init(repo, branch, d): 35 | if not run_no_die(("git", "clone", "--depth", "1", "-b", branch, "--", repo, d)): 36 | git_init(repo, d) 37 | run(("git", "checkout", "-b", branch), cwd=d) 38 | git_set_user(d) 39 | run(("git", "commit", "-m-", "--allow-empty"), cwd=d) 40 | run(("git", "push", "--set-upstream", "origin", branch), cwd=d) 41 | 42 | 43 | def git_save_changed(d): 44 | if len(run_text_out(("git", "status", "--porcelain=v1"), cwd=d).strip()) > 0: 45 | git_set_user(d) 46 | run(("git", "add", "."), cwd=d) 47 | run(("git", "commit", "-m-"), cwd=d) 48 | run(("git", "push"), cwd=d) 49 | else: 50 | log("unchanged") 51 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/OrigMetaImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4actor.Types.{ClName, FieldId, TypeId, TypeKey} 4 | import ee.cone.c4di.c4 5 | import ee.cone.c4proto.MetaProp 6 | 7 | object TypeKeyFullAlias { 8 | def apply(typeKey: TypeKey): String = 9 | s"${typeKey.alias}${if (typeKey.args.isEmpty) "" else s"[${typeKey.args.map(apply).mkString(", ")}]"}" 10 | } 11 | 12 | case class FieldMetaImpl( 13 | id: Long, 14 | name: String, 15 | shortName: Option[String], 16 | typeKey: TypeKey, 17 | metaAttrs: List[AbstractMetaAttr], 18 | annotations: List[String] 19 | ) extends FieldMeta { 20 | lazy val typeAlias: String = TypeKeyFullAlias(typeKey) 21 | lazy val metaProp: MetaProp = MetaProp(Math.toIntExact(id), name, shortName, typeAlias, typeKey) 22 | } 23 | 24 | @c4("ProtoApp") final class OrigMetaRegistryImpl(val all: List[GeneralOrigMeta]) extends OrigMetaRegistry { 25 | val nonGeneral: List[OrigMeta[Product]] = all.distinctBy(_.typeKey).asInstanceOf[List[OrigMeta[Product]]] 26 | val byName: Map[ClName, OrigMeta[Product]] = CheckedMap(nonGeneral.map(meta => meta.cl.getName -> meta)) 27 | val byId: Map[TypeId, OrigMeta[Product]] = CheckedMap(nonGeneral.filter(_.id.nonEmpty).map(meta => meta.id.get -> meta)) 28 | val byTypeKey: Map[TypeKey, OrigMeta[Product]] = CheckedMap(nonGeneral.map(meta => meta.typeKey -> meta)) 29 | def getByCl[Orig <: Product](cl: Class[Orig]): OrigMeta[Orig] = 30 | byName.getOrElse(cl.getName, throw new Exception(s"OrigMetaRegistry doesn't contain ${cl.getName}")).asInstanceOf[OrigMeta[Orig]] 31 | def getById[Orig <: Product](id: TypeId): OrigMeta[Orig] = 32 | byId.getOrElse(id, throw new Exception(s"OrigMetaRegistry doesn't contain ${f"0x$id%04X"}")).asInstanceOf[OrigMeta[Orig]] 33 | } 34 | -------------------------------------------------------------------------------- /gitlab-gen.py: -------------------------------------------------------------------------------- 1 | 2 | import json 3 | import sys 4 | import tempfile 5 | from c4util import changing_text, read_text 6 | from c4util.build import build_cached_by_content, get_main_conf, get_proto, get_image_conf 7 | 8 | 9 | def main(build_path): 10 | temp_root = tempfile.TemporaryDirectory() 11 | get_plain_option = get_main_conf(build_path) 12 | proto_postfix, proto_dir = get_proto(build_path, get_plain_option) 13 | repo, image_tag_prefix = get_image_conf(get_plain_option) 14 | changing_text(f"{temp_root.name}/c4ci_prep", read_text(f"{proto_dir}/ci_prep.py")) 15 | changing_text(f"{temp_root.name}/c4ci_up", read_text(f"{proto_dir}/ci_up.py")) 16 | steps = "\n".join(( 17 | "FROM ubuntu:22.04", 18 | "COPY --from=ghcr.io/conecenter/c4replink:v3kc /install.pl /replink.pl /", 19 | "RUN perl install.pl useradd 1979", 20 | "RUN perl install.pl apt curl ca-certificates python3 git libjson-xs-perl rsync", 21 | "RUN perl install.pl curl https://dl.k8s.io/release/v1.25.3/bin/linux/amd64/kubectl" + 22 | " && chmod +x /tools/kubectl", 23 | "RUN curl -L -o /t.tgz https://github.com/google/go-containerregistry/releases/download/v0.12.1/go-containerregistry_Linux_x86_64.tar.gz" + 24 | " && tar -C /tools -xzf /t.tgz crane && rm /t.tgz", 25 | "COPY c4ci_prep c4ci_up /tools/", "RUN chmod +x /tools/c4ci_prep /tools/c4ci_up", 26 | "ENV PATH=${PATH}:/tools:/tools/linux", 27 | )) 28 | changing_text(f"{temp_root.name}/Dockerfile", steps) 29 | image = build_cached_by_content(temp_root.name, repo, "c4push/.dockerconfigjson") 30 | out = {".handler": {"image": image}} 31 | changing_text(f"{build_path}/gitlab-ci-generated.yml", json.dumps(out, sort_keys=True, indent=4)) 32 | 33 | 34 | main(*sys.argv[1:]) 35 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/SnapshotRemoteImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import java.net.{URLDecoder, URLEncoder} 4 | import java.nio.file.{Files, Paths} 5 | import java.nio.charset.StandardCharsets.UTF_8 6 | import ee.cone.c4di.c4 7 | 8 | @c4("ConfigSimpleSignerApp") final class SimpleSignerImpl( 9 | config: Config, idGenUtil : IdGenUtil 10 | )( 11 | fileName: String = config.get("C4AUTH_KEY_FILE") 12 | )( 13 | val salt: String = new String(Files.readAllBytes(Paths.get(fileName)),UTF_8) 14 | ) extends SimpleSigner { 15 | def sign(data: List[String], until: Long): String = { 16 | val uData = until.toString :: data 17 | val hash = idGenUtil.srcIdFromStrings(salt :: uData:_*) 18 | (hash :: uData).map(URLEncoder.encode(_,"UTF-8")).mkString("=") 19 | } 20 | 21 | def retrieve(check: Boolean): Option[String]=>Option[List[String]] = _.flatMap{ signed => 22 | val hash :: untilStr :: data = signed.split("=", -1).map(URLDecoder.decode(_,"UTF-8")).toList 23 | val until = untilStr.toLong 24 | if(!check) Option(data) 25 | else if(until < System.currentTimeMillis) None 26 | else if(sign(data,until) == signed) Option(data) 27 | else None 28 | } 29 | } 30 | 31 | @c4("TaskSignerApp") final class SnapshotTaskSignerImpl(inner: SimpleSigner)( 32 | val url: String = "/need-snapshot" 33 | ) extends SnapshotTaskSigner { 34 | def sign(task: SnapshotTask, until: Long): String = inner.sign(List(url,task.name) ++ task.offsetOpt, until) 35 | def retrieve(check: Boolean): Option[String]=>Option[SnapshotTask] = 36 | signed => inner.retrieve(check)(signed) match { 37 | case Some(Seq(`url`,"next")) => Option(NextSnapshotTask(None)) 38 | case Some(Seq(`url`,"next", offset)) => Option(NextSnapshotTask(Option(offset))) 39 | case _ => None 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /c4util/cio_preproc.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from json import dumps, loads 4 | 5 | from . import never, never_if 6 | 7 | 8 | def find_def(scope, name): 9 | found = [st[2:] for st in scope[0] if st[0] == "def" and st[1] == name] 10 | # noinspection PyTypeChecker 11 | return ( 12 | find_def(scope[1], name) if len(found) < 1 and scope[1] is not None else 13 | (*(None, *found[0])[-2:], scope) if len(found) == 1 else never(f"non-single {name}") 14 | ) 15 | 16 | 17 | def plan_steps(scope): return [ps for step in scope[0] for ps in plan_step(scope, *step)] 18 | 19 | 20 | def plan_step(scope, op, *step_args): 21 | if op == "def": 22 | return () 23 | elif op == "for": 24 | items, body = step_args 25 | isinstance(items, list) or never("need list") 26 | return [ps for it in items for ps in plan_steps((arg_substitute({"it": it}, body), scope))] 27 | elif op == "call": 28 | msg, = step_args 29 | name = msg["op"] 30 | args, c_scope, p_scope = find_def(scope, name) 31 | bad_args = [] if args is None else sorted(set(msg.keys()).symmetric_difference(["op", *args])) 32 | never_if([f"bad arg {arg} of {name}" for arg in bad_args]) 33 | return plan_steps((arg_substitute(msg, c_scope), p_scope)) 34 | else: 35 | return [(op, *step_args)] 36 | 37 | 38 | def arg_substitute(args, body, die_on_undef=False): 39 | patt = re.compile(r'\{(\w+)}|"@(\w+)"|"strange@(\w+)"') 40 | repl = (lambda a: ( 41 | args[a.group(1)] if a.group(1) in args else 42 | dumps(args[a.group(2)]) if a.group(2) in args else 43 | dumps([str(n) for n in range(args[a.group(3)])]) if a.group(3) in args else 44 | never(f'missing {a.group(0)}') if die_on_undef else a.group(0) 45 | )) 46 | return loads(patt.sub(repl, dumps(body))) -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/tests/GeneratorTest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.tests 2 | 3 | import ee.cone.c4actor.Types.SrcId 4 | import ee.cone.c4actor.{IdMetaAttr, Meta, NameMetaAttr, TestProtocol} 5 | import ee.cone.c4assemble.{assemble, ignore} 6 | import ee.cone.c4proto._ 7 | 8 | @protocol /*(Cat1)*/ object TestProtocolM { 9 | 10 | trait TestTrait 11 | 12 | @master("123") 13 | @ShortName("KEK") 14 | @GenLens 15 | @Id(1) 16 | @Meta(NameMetaAttr("321")) 17 | @Cat(Cat2, Cat1) case class D_LUL( 18 | @Meta(NameMetaAttr("123"), IdMetaAttr(1)) @ShortName("LUL") @Id(2) test: String 19 | ) extends TestTrait 20 | 21 | @Id(2) 22 | @Cat(Cat1) case class D_LUL2( 23 | @Id (1) id1: SrcId, 24 | @Id (2) id2: SrcId, 25 | @Id (3) id3: SrcId, 26 | @Id (4) id4: SrcId, 27 | @Id (5) id5: SrcId, 28 | @Id (6) id6: SrcId, 29 | @Id (7) id7: SrcId, 30 | @Id (8) id8: SrcId, 31 | @Id (9) id9: SrcId, 32 | @Id (10) id10: SrcId, 33 | @Id (11) id11: SrcId, 34 | @Id (12) id12: SrcId, 35 | @Id (13) id13: SrcId, 36 | @Id (14) id14: SrcId, 37 | @Id (15) id15: SrcId, 38 | @Id (16) id16: SrcId, 39 | @Id (17) id17: SrcId, 40 | @Id (18) id18: SrcId, 41 | @Id (19) id19: SrcId, 42 | @Id (20) id20: SrcId, 43 | @Id (21) id21: SrcId, 44 | @Id (22) id22: SrcId, 45 | ) 46 | 47 | } 48 | 49 | case object Cat1 extends DataCategory { 50 | def uid: Int = 0x001 51 | } 52 | 53 | case object Cat2 extends DataCategory { 54 | def uid: Int = 0x002 55 | } 56 | 57 | object TestProtocolMain { 58 | def main(args: Array[String]): Unit = { 59 | println( 60 | "commented due to the failure of cats empire" 61 | // TestProtocolM.adapters.map(_.categories) 62 | ) 63 | } 64 | } 65 | 66 | @assemble class TestAssembleBase { 67 | @ignore def test: Int = 1 68 | } 69 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/dep_impl/DepMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.dep_impl 2 | 3 | import ee.cone.c4actor.dep._ 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4assemble.Assemble 6 | import ee.cone.c4di.{Component, ComponentsApp} 7 | 8 | import ee.cone.c4actor.ComponentProvider.provide 9 | 10 | trait DepHandlersApp extends ComponentsApp { 11 | def depHandlers: List[DepHandler] = Nil 12 | private lazy val depHandlersComponent = provide(classOf[DepHandler], () => depHandlers) 13 | override def components: List[Component] = depHandlersComponent :: super.components 14 | } 15 | 16 | trait DepResponseFiltersApp extends ComponentsApp { 17 | def depFilters: List[DepResponseForwardFilter] = Nil 18 | private lazy val depFiltersComponent = provide(classOf[DepResponseForwardFilter], () => depFilters) 19 | override def components: List[Component] = depFiltersComponent :: super.components 20 | } 21 | 22 | trait DepAssembleApp extends DepAssembleCompApp with ComponentProviderApp { 23 | lazy val depFactory: DepFactory = resolveSingle(classOf[DepFactory]) 24 | lazy val depAskFactory: DepAskFactory = resolveSingle(classOf[DepAskFactory]) 25 | lazy val depResponseFactory: DepResponseFactory = resolveSingle(classOf[DepResponseFactory]) 26 | lazy val depRequestFactory: DepRequestFactory = resolveSingle(classOf[DepRequestFactory]) 27 | } 28 | 29 | /// 30 | 31 | trait AskByPKsApp { 32 | def askByPKs: List[AbstractAskByPK] = Nil 33 | } 34 | 35 | trait ByPKRequestHandlerApp extends ByPKRequestHandlerCompApp with AssemblesApp with AskByPKsApp with ComponentsApp with ComponentProviderApp { 36 | lazy val askByPKFactory: AskByPKFactory = resolveSingle(classOf[AskByPKFactory]) 37 | private lazy val askByPKsComponent = provide(classOf[AbstractAskByPK], () => askByPKs) 38 | override def components: List[Component] = askByPKsComponent :: super.components 39 | } 40 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/ConsoleAssembleProfiler.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor.QProtocol.N_Update 5 | import ee.cone.c4assemble.{AggrDOut, Join, JoiningProfiling, WorldTransition} 6 | import ee.cone.c4assemble.Types.{DPIterable, Index, ProfilingLog} 7 | 8 | import scala.collection.immutable.Seq 9 | import scala.concurrent.Future 10 | 11 | case object ConsoleAssembleProfiler extends AssembleProfiler { 12 | def createJoiningProfiling(localOpt: Option[Context]): JoiningProfiling = ConsoleProfiling 13 | 14 | def addMeta(transition: WorldTransition, updates: Seq[QProtocol.N_Update]): Future[Seq[N_Update]] = 15 | Future.successful(updates) 16 | } 17 | 18 | case object ConsoleProfiling extends JoiningProfiling with LazyLogging { 19 | def time: Long = System.nanoTime 20 | 21 | def handle(join: Join, stage: Long, start: Long, wasLog: ProfilingLog): ProfilingLog = { 22 | val timeNano: Long = (System.nanoTime - start) / 10000 23 | val timeFront: Double = timeNano / 100.0 24 | logger.debug(s"rule ${join.assembleName}-${join.name}-$stage for ${getColoredPeriod(timeFront)} ms") 25 | wasLog 26 | } 27 | 28 | def getColoredPeriod: Double => String = { 29 | case i if i < 200 => PrintColored.makeColored("g")(i.toString) 30 | case i if i >= 200 && i < 500 => PrintColored.makeColored("y")(i.toString) 31 | case i if i >= 500 => PrintColored.makeColored("r")(i.toString) 32 | } 33 | 34 | // def getColoredCount: Long => String = { 35 | // case i if i < 100 => PrintColored.makeColored("g")(i.toString) 36 | // case i if i >= 100 && i < 1000 => PrintColored.makeColored("y")(i.toString) 37 | // case i if i >= 1000 => PrintColored.makeColored("r")(i.toString) 38 | // } 39 | def handle(join: Join, result: Seq[AggrDOut], wasLog: ProfilingLog): ProfilingLog = wasLog 40 | } 41 | -------------------------------------------------------------------------------- /ci_prep.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 -u 2 | 3 | import subprocess 4 | import sys 5 | import os 6 | from tempfile import TemporaryDirectory 7 | from pathlib import Path 8 | from json import loads 9 | from argparse import ArgumentParser 10 | 11 | 12 | def run(args, **opt): 13 | print("running: " + " ".join(args), file=sys.stderr) 14 | return subprocess.run(args, check=True, **opt) 15 | 16 | 17 | def read_json(path): 18 | return loads(Path(path).read_text(encoding="utf-8", errors="strict")) 19 | 20 | 21 | def get_plain_options(plain_conf, k): 22 | return [line[2] for line in plain_conf if line[0] == k] 23 | 24 | 25 | def main(): 26 | parser = ArgumentParser() 27 | parser.add_argument("--context", required=True) 28 | parser.add_argument("--c4env", required=True) 29 | parser.add_argument("--state", required=True) 30 | parser.add_argument("--info-out", required=True) 31 | opt = parser.parse_args() 32 | context = opt.context 33 | plain_conf = read_json(f"{context}/c4dep.main.json") 34 | replink, = get_plain_options(plain_conf, "C4REPLINK") 35 | proto_postfix, = get_plain_options(plain_conf, "C4PROTO_POSTFIX") 36 | deploy_context, = get_plain_options(plain_conf, "C4DEPLOY_CONTEXT") 37 | dir_life = TemporaryDirectory() 38 | dir_nm = dir_life.name 39 | if os.environ.get("C4DEBUG_GIT"): 40 | run(("rsync", "-a", f"{context}/", f"{dir_nm}/")) 41 | else: 42 | run(("git", "clone", context, dir_nm)) 43 | run(("/replink.pl",), env={"C4REPO_MAIN_CONF": f"{dir_nm}/{replink}"}) 44 | args = ("--context", dir_nm, "--c4env", opt.c4env, "--state", opt.state, "--info-out", opt.info_out) 45 | run(("python3", "-u", f"{dir_nm}/{proto_postfix}/build_remote.py", "ci_prep", *args), env={ 46 | "C4DEPLOY_CONTEXT": deploy_context, "PATH": os.environ["PATH"], "KUBECONFIG": os.environ["KUBECONFIG"] 47 | }) 48 | 49 | main() 50 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/sandbox/SandboxBackEnd.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.sandbox 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor.Types.SrcId 5 | import ee.cone.c4actor._ 6 | import ee.cone.c4actor.sandbox.SandboxProtocol.D_Sandbox 7 | import ee.cone.c4di.{c4, c4app} 8 | 9 | /* 10 | To start this app type the following into console: 11 | C4STATE_TOPIC_PREFIX=ee.cone.c4actor.sandbox.SandboxProject sbt ~'c4actor-extra-examples/runMain ee.cone.c4actor.ServerMain' 12 | */ 13 | 14 | @c4("SandboxProjectApp") final class SandboxProject( 15 | execution: Execution, toUpdate: ToUpdate, contextFactory: ContextFactory, 16 | getD_Sandbox: GetByPK[D_Sandbox], 17 | ) extends Executable with LazyLogging { 18 | def run(): Unit = { 19 | // val updates: List[QProtocol.N_Update] = worldUpdate.map(rec => toUpdate.toUpdate(rec)).toList 20 | val local: Context = contextFactory.updated(Nil) 21 | //val nGlobal: Context = ReadModelAddKey.of(context)(updates)(context) 22 | val neededSrcId = "123" 23 | 24 | val sandboxOrigMap: Map[SrcId, D_Sandbox] = getD_Sandbox.ofA(local) 25 | val someOrig: Option[D_Sandbox] = sandboxOrigMap.get(neededSrcId) 26 | 27 | 28 | println(someOrig) 29 | execution.complete() 30 | } 31 | } 32 | 33 | @c4app trait SandboxProjectAppBase extends TestVMRichDataApp 34 | with ExecutableApp 35 | with VMExecutionApp 36 | with SandboxProtocolsApp 37 | with SandboxJoinersApp 38 | 39 | /* 40 | object ValueAssembleProfiler extends AssembleProfiler { 41 | def get(ruleName: String): String => Int => Unit = startAction => { 42 | val startTime = System.currentTimeMillis 43 | finalCount => { 44 | val period = System.currentTimeMillis - startTime 45 | println(s"assembling by ${Thread.currentThread.getName} rule $ruleName $startAction $finalCount items in $period ms") 46 | } 47 | } 48 | } 49 | */ 50 | -------------------------------------------------------------------------------- /micro/memresize/README.md: -------------------------------------------------------------------------------- 1 | # memresize 2 | 3 | Memresize watches pods in a single namespace, inspects the `main` container's memory usage from the metrics.k8s.io API, and adjusts that container's memory *request* in-place. Only pod names matching a configurable regex are considered, keeping the agent focused on a subset of workloads. 4 | 5 | ## Requirements 6 | - Kubernetes cluster with the `InPlacePodVerticalScaling` feature gate enabled (v1.32+). 7 | - Metrics server exposing `/apis/metrics.k8s.io/v1beta1/*`. 8 | - Service account RBAC permitting `get` on pods and metrics plus `patch` on pods (with the `resize` subresource). 9 | 10 | ## Configuration 11 | Set the following environment variables to tune behaviour. Values shown in **bold** are defaults. 12 | 13 | | Variable | Default | Purpose | 14 | | --- | --- | --- | 15 | | `C4KUBECONFIG` | *(required)* | Path to kubeconfig used for all calls. | 16 | | `C4MEM_KUBE_CONTEXT` | *(required)* | Kube context to target. | 17 | | `C4MEM_KUBE_NS` | *(required)* | Namespace containing the pods to manage. | 18 | | `C4MEM_POD_LIKE` | **`^de-`** | Regex; pod name must match to be considered. | 19 | | `C4MEM_SCALE_UP_TRIGGER` | **`1.2`** | Resize upward when usage/request ≥ threshold. | 20 | | `C4MEM_SCALE_DOWN_TRIGGER` | **`0.5`** | Resize downward when usage/request ≤ threshold. | 21 | | `C4MEM_SLEEP_FOR_SECONDS` | **`120`** | Delay between iterations. | 22 | | `C4MEM_DRY_RUN` | *(absent)* | Set to `1` to log patches without applying them. | 23 | 24 | The agent understands memory quantities reported in `Ki`, `Mi`, or `Gi`. Usage data comes from the metrics API, while requests are read from the live pod spec. 25 | 26 | ## Local run 27 | ``` 28 | C4KUBECONFIG=~/.kube/config \ 29 | C4MEM_KUBE_CONTEXT=clusterA \ 30 | C4MEM_KUBE_NS=test \ 31 | python memresize/main.py 32 | ``` 33 | Toggle dry-run behaviour by exporting `C4MEM_DRY_RUN=1` until you're comfortable with the suggested patches. 34 | -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4gate/deep_session/DeepSessionDataAssemble.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4gate.deep_session 2 | 3 | import ee.cone.c4actor.LifeTypes.Alive 4 | import ee.cone.c4actor.Types.SrcId 5 | import ee.cone.c4actor.{AssembleName, MortalFactory, WithPK} 6 | import ee.cone.c4assemble.Types.{Each, Values} 7 | import ee.cone.c4assemble.{Assemble, assemble, by} 8 | import ee.cone.c4gate.deep_session.DeepSessionDataProtocol.{U_RawRoleData, U_RawUserData} 9 | 10 | object DeepSessionDataAssembles { 11 | def apply(mortal: MortalFactory, userModel: Class[_ <: Product], roleModel: Class[_ <: Product]): List[Assemble] = 12 | mortal(classOf[U_RawUserData]) :: 13 | mortal(classOf[U_RawRoleData]) :: 14 | new RawUserDataAssemble(userModel) :: 15 | new RawRoleDataAssemble(roleModel) :: Nil 16 | } 17 | 18 | @assemble class RawUserDataAssembleBase[User <: Product](modelCl: Class[User]) 19 | extends AssembleName("RawUserDataAssemble", modelCl) { 20 | type UserId = SrcId 21 | 22 | def RawUserDataByRoleId( 23 | srcId: SrcId, 24 | rawData: Each[U_RawUserData] 25 | ): Values[(UserId, U_RawUserData)] = 26 | List(rawData.userId -> rawData) 27 | 28 | def ModelWithRawUserDataLife( 29 | modelId: SrcId, 30 | @by[UserId] rawData: Each[U_RawUserData], 31 | model: Each[User] 32 | ): Values[(Alive, U_RawUserData)] = List(WithPK(rawData)) 33 | } 34 | 35 | @assemble class RawRoleDataAssembleBase[Role <: Product](roleCl: Class[Role]) 36 | extends AssembleName("RawRoleDataAssemble", roleCl) { 37 | type RoleId = SrcId 38 | 39 | def RawRoleDataByRoleId( 40 | srcId: SrcId, 41 | rawData: Each[U_RawRoleData] 42 | ): Values[(RoleId, U_RawRoleData)] = List(rawData.roleId -> rawData) 43 | 44 | def ModelWithRawRoleDataLife( 45 | modelId: SrcId, 46 | @by[RoleId] rawData: Each[U_RawRoleData], 47 | model: Each[Role] 48 | ): Values[(Alive, U_RawRoleData)] = List(WithPK(rawData)) 49 | } -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor/ComponentApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4assemble.Single 4 | import ee.cone.c4di.{AbstractComponents, AutoMixer, Component, TypeKey} 5 | 6 | import scala.concurrent.duration.Duration 7 | import scala.concurrent.{Await, Future} 8 | 9 | object ComponentRegistry { 10 | val debug: Boolean = Option(System.getenv("C4DEBUG_COMPONENTS")).nonEmpty 11 | def isRegistry: Component=>Boolean = { 12 | val clName = classOf[AbstractComponents].getName 13 | c => c.in match { 14 | case Seq(inKey) if inKey.clName == clName => true 15 | case _ => false 16 | } 17 | } 18 | def apply(app: AbstractComponents): ComponentRegistry = 19 | Single(Single(app.components.filter(isRegistry).distinct).create(Seq(app))) 20 | .asInstanceOf[ComponentRegistry] 21 | 22 | def getAll(mixer: AutoMixer): List[Component] = { // todo move to impl? 23 | import scala.concurrent.ExecutionContext.Implicits.global 24 | def mixersOf( mixer: AutoMixer, was: (Set[AutoMixer], List[AutoMixer])): (Set[AutoMixer], List[AutoMixer]) = { 25 | val (wasS, wasL) = was 26 | if (wasS(mixer)) was else mixer.dependencies.foldRight((wasS + mixer, mixer :: wasL))(mixersOf) 27 | } 28 | val (_, mixers) = mixersOf(mixer, (Set.empty, Nil)) 29 | if(debug) println(s"mixers found: ${mixers.size}") 30 | val componentsF = Future.sequence(mixers.map(v => Future(v.getComponents()))).map(_.flatten) 31 | val components = Await.result(componentsF, Duration.Inf) 32 | if(debug) println(s"mixer components found ${components.size}") 33 | components 34 | } 35 | } 36 | 37 | trait ComponentRegistry { 38 | def resolveKey(key: TypeKey): DeferredSeq[Any] 39 | def resolve[T](cl: Class[T], args: Seq[TypeKey]): DeferredSeq[T] 40 | def components: Seq[Component] 41 | } 42 | 43 | trait DeferredSeq[+T] { 44 | def value: Seq[T] 45 | } 46 | 47 | case class StrictTypeKey[T](value: TypeKey) -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4actor_repl_impl/Repl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor_repl_impl 2 | 3 | import java.util.concurrent.atomic.AtomicReference 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4actor.Types.{SrcId, TxEvents} 6 | import ee.cone.c4assemble._ 7 | import ammonite.sshd._ 8 | import ammonite.util.Bind 9 | import ee.cone.c4di.c4 10 | import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator 11 | 12 | @c4("SSHDebugApp") final case class SSHDebugTx(srcId: SrcId="SSHDebug")( 13 | qMessages: QMessages, replace: Replace, 14 | ) extends SingleTxTr with Executable with Early { 15 | private val ref = new AtomicReference[ReadModel](replace.emptyReadModel) 16 | def run(): Unit = { 17 | def tx(f: Context=>Object): List[_] = { 18 | val assembled = ref.get 19 | f(new Context(assembled, Map.empty)) match { 20 | case local: Context => 21 | val nLocal = qMessages.send(local) 22 | Nil 23 | case res: List[_] => res 24 | } 25 | } 26 | val server = new SshdRepl( 27 | SshServerConfig( 28 | address = "localhost", // or "0.0.0.0" for public-facing shells 29 | port = 22222, 30 | publicKeyAuthenticator = Option(AcceptAllPublickeyAuthenticator.INSTANCE) 31 | ), 32 | replArgs = List(Bind[(Context=>Object)=>Object]("tx",tx)) 33 | ) 34 | server.start() 35 | } 36 | def transform(local: Context): TxEvents = { 37 | ref.set(local.assembled) 38 | Nil 39 | } 40 | } 41 | 42 | 43 | /* 44 | byPK(classOf[T]) 45 | add(lEvents) 46 | commit() 47 | rollback() 48 | */ 49 | /* 50 | import ee.cone.c4actor._ 51 | import ee.cone.c4gate._ 52 | tx(ByPK(classOf[AlienProtocol.U_FromAlienState]).of(_).values.toList.sortBy(_.sessionKey)) 53 | tx(txAdd.add(LEvent.delete(AlienProtocol.U_FromAlienState("61297c47-c5de-4fd9-add9-1967615a44a8", "https://skh.dev.cone.ee/react-app.html", "61297c47-c5de-4fd9-add9-1967615a44a8", None)))) 54 | */ 55 | -------------------------------------------------------------------------------- /c4util/notify.py: -------------------------------------------------------------------------------- 1 | 2 | import re 3 | from json import dumps 4 | import http.client 5 | from pathlib import Path 6 | 7 | from . import http_check, http_exchange, changing_text, read_json, run 8 | from .cmd import get_cmd 9 | 10 | # "notify_started": lambda opt: ny.notify_started(get_dir, ny.notify_create_requests( 11 | # access(deploy_context, opt["auth"]), opt["url"], 12 | # time.time(), opt["work_hours"], opt["valid_hours"], log_message(env, read_text(get_dir("log_path"))) 13 | # )), 14 | # "notify_succeeded": lambda: ny.notify_succeeded(get_dir), 15 | # todo replace "log_path" 16 | 17 | # immutable, api specific: 18 | def notify_create_requests(auth, full_url, now, work_hours, valid_hours, descr): 19 | host, url = re.fullmatch(r'https://([^/]+)(.*)', full_url).group(1, 2) 20 | headers = {"Authorization": auth, "Content-Type": "application/json"} 21 | return { 22 | status: [host, "PUT", url, { 23 | "status": status, "description": descr, 24 | "due_date": int(now*1000)+int(hours)*60*60*1000, "due_date_time": True, 25 | }, headers] 26 | for status, hours in (("started", work_hours), ("succeeded", valid_hours), ("failed", 0)) 27 | } 28 | 29 | 30 | # general: 31 | 32 | #todo fix fin-ion 33 | def notify_started(get_dir, requests): 34 | notify_send_req(*requests["started"]) 35 | changing_text(get_dir("fin.json"), dumps(get_cmd(notify_send_req, *requests["failed"]))) 36 | changing_text(get_dir("notify_succeeded.json"), dumps(get_cmd(notify_send_req, *requests["succeeded"]))) 37 | 38 | 39 | def notify_succeeded(get_dir): 40 | run(read_json(get_dir("notify_succeeded.json"))) 41 | Path(get_dir("fin.json")).unlink() 42 | 43 | 44 | def notify_send_req(host, method, url, data, headers): 45 | conn = http.client.HTTPSConnection(host, None) 46 | # log([host, method, url, data, headers]) 47 | http_check(*http_exchange(conn, method, url, dumps(data).encode("utf-8"), headers)) 48 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4ui/ByLocationHashView.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor.QProtocol.S_Firstborn 4 | import ee.cone.c4actor.Types.{LEvents, SrcId} 5 | import ee.cone.c4actor.{Context, WithPK} 6 | import ee.cone.c4assemble.Types.{Each, Values} 7 | import ee.cone.c4assemble.{by, c4assemble} 8 | import ee.cone.c4di._ 9 | import ee.cone.c4gate._ 10 | import ee.cone.c4vdom.Receiver 11 | import ee.cone.c4vdom.Types.ViewRes 12 | import okio.ByteString 13 | 14 | trait ByLocationHashView extends View 15 | 16 | @c4assemble("PublicViewAssembleApp") class PublicViewAssembleBase(views: List[ByLocationHashView]) { 17 | type LocationHash = String 18 | def joinByLocationHash( 19 | key: SrcId, 20 | fromAlien: Each[FromAlienTask] 21 | ): Values[(LocationHash,FromAlienTask)] = List(fromAlien.locationHash -> fromAlien) 22 | 23 | def joinPublicView( 24 | key: SrcId, 25 | firstborn: Each[S_Firstborn] 26 | ): Values[(SrcId,ByLocationHashView)] = for { 27 | view <- views 28 | } yield WithPK(view) 29 | 30 | def join( 31 | key: SrcId, 32 | publicView: Each[ByLocationHashView], 33 | @by[LocationHash] task: Each[FromAlienTask] 34 | ): Values[(SrcId,View)] = 35 | List(WithPK(AssignedPublicView(task.branchKey,task,publicView))) 36 | } 37 | 38 | case class AssignedPublicView(branchKey: SrcId, task: FromAlienTask, currentView: View) extends View { 39 | def view: Context => ViewRes = 40 | CurrentSessionKey.set(task.fromAlienState.sessionKey).andThen(currentView.view) 41 | } 42 | 43 | //// 44 | 45 | @c4("TestTodoApp") final class ReactHtmlProvider extends PublishFromStringsProvider { 46 | def get: List[(String, String)] = { 47 | val now = System.currentTimeMillis 48 | List( 49 | "/ws-app.html" -> ( 50 | """""" + 51 | s"""""" 52 | ), 53 | ) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4ui/ListImpl.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import java.text.{DecimalFormat, DecimalFormatSymbols, NumberFormat} 4 | import ee.cone.c4di._ 5 | import ee.cone.c4actor.Context 6 | import ee.cone.c4ui.FrontTypes.Em 7 | import ee.cone.c4vdom._ 8 | 9 | @c4("UICompApp") final class ListJsonAdapterProvider(util: TagJsonUtils){ 10 | @provide def forString: Seq[JsonValueAdapter[String]] = 11 | List(util.jsonValueAdapter((value, builder) => builder.just.append(value))) 12 | @provide def forToJson: Seq[JsonValueAdapter[ToJson]] = 13 | List(util.jsonValueAdapter((value,builder) => value.appendJson(builder))) 14 | @provide def forInt: Seq[JsonValueAdapter[Int]] = 15 | List(util.jsonValueAdapter((value, builder) => builder.just.append(value))) 16 | /* 17 | @provide def forLong: Seq[JsonValueAdapter[Long]] = 18 | We can not send Long, because JS can add error to it when decoding 19 | e.g. 9223372036854775807 = 9223372036854776000 for JS 20 | use String instead 21 | */ 22 | @provide def forBoolean: Seq[JsonValueAdapter[Boolean]] = 23 | List(util.jsonValueAdapter((value,builder) => builder.just.append(value))) 24 | // 25 | @provide def forCSSClassName: Seq[JsonValueAdapter[CSSClassName]] = 26 | List(util.jsonValueAdapter((value, builder) => builder.just.append(value.name))) 27 | @provide def forReceiver: Seq[JsonValueAdapter[Receiver[Context]]] = 28 | List(util.jsonValueAdapter((value, builder) => builder.just.append("send"))) 29 | } 30 | 31 | @c4("UICompApp") final class EmAdapterProvider(util: TagJsonUtils)( 32 | symbols: DecimalFormatSymbols = { 33 | val result = DecimalFormatSymbols.getInstance 34 | result.setDecimalSeparator('.') 35 | result 36 | } 37 | )( 38 | emFormat: DecimalFormat = new DecimalFormat("#0.###", symbols) 39 | ) { 40 | @provide def emAdapter: Seq[JsonValueAdapter[Em]] = 41 | List(util.jsonValueAdapter((value, builder) => builder.just.append(value, emFormat))) 42 | } -------------------------------------------------------------------------------- /base_server/src/main/scala/ee/cone/c4gate_server/LogPurging.scala: -------------------------------------------------------------------------------- 1 | 2 | package ee.cone.c4gate_server 3 | 4 | import com.typesafe.scalalogging.LazyLogging 5 | import ee.cone.c4actor._ 6 | import ee.cone.c4actor.Types.NextOffset 7 | import ee.cone.c4di.c4 8 | 9 | import scala.annotation.tailrec 10 | import scala.concurrent.Future 11 | 12 | @c4("SnapshotMakingApp") final class LogPurging( 13 | purging: QPurging, 14 | lister: SnapshotLister, 15 | keepLogForSnapshotCount: Int = 10, 16 | s3LogPurger: S3LogPurger, 17 | currentTxLogName: CurrentTxLogName, 18 | ) extends Executable { 19 | def run(): Unit = 20 | purging.process(currentTxLogName, purger => iteration(purger, None)) 21 | @tailrec private def iteration(purger: QPurger, wasOffset: Option[NextOffset]): Unit = { 22 | val (need, noNeed) = lister.listWithMTime.sortBy(_.snapshot.offset).reverse 23 | .splitAt(keepLogForSnapshotCount) 24 | val willOffset = noNeed.headOption.map(_.snapshot.offset) 25 | if (wasOffset == willOffset) Thread.sleep(60000) 26 | else { 27 | willOffset.foreach(purger.delete(_)) 28 | need.map(_.mTime).minOption.foreach{ mTime => 29 | s3LogPurger.delete(currentTxLogName, mTime - 5*60*1000) 30 | } 31 | } 32 | iteration(purger,willOffset) 33 | } 34 | } 35 | 36 | @c4("SnapshotMakingApp") final class S3LogPurger( 37 | loBroker: LOBroker, 38 | s3: S3Manager, 39 | s3L: S3Lister, 40 | execution: Execution, 41 | ) extends LazyLogging { 42 | def delete(txLogName: TxLogName, beforeMillis: Long): Unit = execution.fatal{ implicit ec => 43 | logger.debug(s"delete before ms: $beforeMillis") 44 | for{ 45 | dataOpt <- s3L.list(txLogName,loBroker.bucketPostfix) 46 | deleted <- Future.sequence( 47 | for { 48 | (name,tStr) <- dataOpt.toList.flatten if s3L.parseTime(tStr) < beforeMillis 49 | } yield s3.delete(s3.join(txLogName,s"${loBroker.bucketPostfix}/$name")) 50 | ) 51 | } yield deleted 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /base_examples/src/main/scala/ee/cone/c4actor/BaseExamplesMix.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor 2 | 3 | import ee.cone.c4di.c4app 4 | 5 | trait BaseExamplesTestApp extends TestVMRichDataCompApp 6 | with SimpleAssembleProfilerCompApp with VMExecutionApp with ExecutableApp 7 | 8 | @c4app class ConnTestAppBase extends BaseExamplesTestApp 9 | 10 | //C4STATE_TOPIC_PREFIX=ee.cone.c4actor.ConnTestApp sbt ~'c4actor-base-examples/run-main ee.cone.c4actor.ServerMain' 11 | 12 | @c4app class EachTestAppBase extends BaseExamplesTestApp 13 | 14 | // C4STATE_TOPIC_PREFIX=ee.cone.c4actor.EachTestApp sbt ~'c4actor-base-examples/run-main ee.cone.c4actor.ServerMain' 15 | 16 | @c4app class JoinAllTestAppBase extends BaseExamplesTestApp 17 | 18 | // C4STATE_TOPIC_PREFIX=ee.cone.c4actor.JoinAllTestApp sbt ~'c4actor-base-examples/run-main ee.cone.c4actor.ServerMain' 19 | trait JustJoinTestAppBase 20 | trait RevRelFactoryImplAppBase 21 | @c4app class RRTest1AppBase extends BaseExamplesTestApp with RevRelFactoryImplApp with JustJoinTestApp 22 | @c4app class RRTest2AppBase extends BaseExamplesTestApp with RevRelFactoryImplApp with JustJoinTestApp 23 | @c4app class RRTest3AppBase extends BaseExamplesTestApp with RevRelFactoryImplApp with JustJoinTestApp 24 | 25 | // C4STATE_TOPIC_PREFIX=ee.cone.c4actor.RRTest1App sbt ~'c4actor-base-examples/run-main ee.cone.c4actor.ServerMain' 26 | 27 | trait AssemblerTestAppBase 28 | @c4app class SimpleAssemblerTestAppBase extends AssemblerTestApp with BaseExamplesTestApp 29 | @c4app class NotEffectiveAssemblerTestAppBase extends AssemblerTestApp with BaseExamplesTestApp 30 | 31 | @c4app class HashSearchTestAppBase extends BaseExamplesTestApp 32 | 33 | @c4app class ProtoAdapterTestAppBase extends ExecutableApp with VMExecutionApp 34 | with BaseApp with ProtoApp with BigDecimalApp with GzipRawCompressorApp 35 | 36 | @c4app class DeadlockTestAppBase extends DeadlockDetectApp with VMExecutionApp with ExecutableApp with BaseApp 37 | 38 | @c4app class OrigNSTestAppBase extends BaseExamplesTestApp -------------------------------------------------------------------------------- /extra_lib/src/main/scala/ee/cone/c4actor/hashsearch/rangers/HashSearchRangerRegistry.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.hashsearch.rangers 2 | 3 | import ee.cone.c4actor.{ComponentProviderApp, QAdapterRegistry, QAdapterRegistryApp} 4 | import ee.cone.c4di.{Component, ComponentsApp, c4} 5 | import ee.cone.c4actor.ComponentProvider.provide 6 | 7 | trait HashSearchRangerRegistryApp { 8 | def hashSearchRangerRegistry: HashSearchRangerRegistry 9 | } 10 | 11 | trait HashSearchRangersApp extends ComponentsApp { 12 | private lazy val hashSearchRangersComponent = 13 | provide(classOf[RangerWithClProvider], ()=>Seq(RangerWithClProvider(hashSearchRangers))) 14 | override def components: List[Component] = hashSearchRangersComponent :: super.components 15 | def hashSearchRangers: List[RangerWithCl[_ <: Product, _]] = Nil 16 | } 17 | 18 | trait HashSearchRangerRegistryMixBase extends ComponentProviderApp with HashSearchRangerRegistryApp with HashSearchRangersApp { 19 | def hashSearchRangerRegistry: HashSearchRangerRegistry = resolveSingle(classOf[HashSearchRangerRegistry]) 20 | } 21 | 22 | trait HashSearchRangerRegistry { 23 | def getByByIdUntyped(byId: Long): Option[RangerWithCl[_ <: Product, _]] 24 | 25 | def getAll: List[RangerWithCl[Product, Any]] 26 | } 27 | 28 | case class RangerWithClProvider(values: List[RangerWithCl[_ <: Product, _]]) 29 | 30 | @c4("HashSearchRangerRegistryMix") final case class HashSearchRangerRegistryImpl( 31 | providers: List[RangerWithClProvider], 32 | qAdapterRegistry: QAdapterRegistry 33 | ) extends HashSearchRangerRegistry { 34 | private def rangers = providers.flatMap(_.values).distinct 35 | lazy val byIdMap: Map[Long, RangerWithCl[_ <: Product, _]] = 36 | rangers.map(ranger => qAdapterRegistry.byName(ranger.byCl.getName).id -> ranger).toMap 37 | 38 | def getByByIdUntyped(byId: Long): Option[RangerWithCl[_ <: Product, _]] = 39 | byIdMap.get(byId) 40 | 41 | def getAll: List[RangerWithCl[Product, Any]] = rangers.map(_.asInstanceOf[RangerWithCl[Product, Any]]) 42 | } 43 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/tests/SnapshotParser.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.tests 2 | 3 | import java.nio.file.{Files, Paths} 4 | 5 | import ee.cone.c4actor._ 6 | import ee.cone.c4actor_kafka_impl.LZ4DeCompressorApp 7 | import ee.cone.c4proto.ToByteString 8 | import okio.ByteString 9 | 10 | //C4STATE_TOPIC_PREFIX=ee.cone.c4actor.tests.SnapshotParserApp sbt ~'c4actor-extra-examples/runMain ee.cone.c4actor.ServerMain' 11 | 12 | class SnapshotParser(execution: Execution, toUpdate: ToUpdate, snapshotLoader: SnapshotLoader, qAdapterRegistry: QAdapterRegistry) extends Executable { 13 | def run(): Unit = { 14 | println(new java.io.File(".").getCanonicalPath) 15 | val hashFromData = SnapshotUtilImpl.hashFromData(Files.readAllBytes(Paths.get("/c4db/home/c4proto/c4actor-extra-examples/0000000000000000-92b87c05-294d-3c1d-b443-fb83bdc71d20-c-lz4"))) 16 | println(hashFromData) 17 | val fromName = SnapshotUtilImpl.hashFromName(RawSnapshot("0000000000000000-92b87c05-294d-3c1d-b443-fb83bdc71d20-c-lz4")).get.uuid 18 | println(hashFromData, fromName) 19 | val sn = snapshotLoader.load(RawSnapshot("0000000000000000-92b87c05-294d-3c1d-b443-fb83bdc71d20-c-lz4")) 20 | val updates = sn.toList.flatMap(toUpdate.toUpdates(_,"test")) 21 | println(updates.filter(_.flags != 0L).mkString("\n")) 22 | execution.complete() 23 | } 24 | } 25 | 26 | class SnapshotParserApp 27 | extends ToStartApp 28 | with VMExecutionApp 29 | with ExecutableApp 30 | with RichDataApp 31 | with EnvConfigApp 32 | with LZ4DeCompressorApp 33 | { 34 | lazy val loader = new RawSnapshotLoader { 35 | def load(snapshot: RawSnapshot): ByteString = { 36 | ??? //snapshots goes to s3 37 | //val path = Paths.get(config.get("C 4 D A T A _ D I R")).resolve(snapshot.relativePath) 38 | //ToByteString(Files.readAllBytes(path)) 39 | } 40 | } 41 | 42 | override def toStart: List[Executable] = new SnapshotParser(execution, toUpdate, new SnapshotLoaderImpl(loader), qAdapterRegistry) :: super.toStart 43 | } 44 | -------------------------------------------------------------------------------- /base_lib/src/main/scala/ee/cone/c4ui/UIApi.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import ee.cone.c4actor.Types.{LEvents, SrcId, TxEvents} 4 | import ee.cone.c4actor.{Context, TransientLens} 5 | import ee.cone.c4actor_branch.BranchTask 6 | import ee.cone.c4actor_branch.BranchTypes.BranchResult 7 | import ee.cone.c4gate.AlienProtocol.U_FromAlienState 8 | import ee.cone.c4vdom.Types.ViewRes 9 | import ee.cone.c4vdom.{Receiver, VDomLens, VDomState, VDomView} 10 | 11 | trait View extends VDomView[Context] with Product 12 | 13 | trait UntilPolicy { 14 | def wrap(view: Context=>ViewRes): Context=>ViewRes 15 | } 16 | 17 | case object VDomStateKey extends TransientLens[Option[VDomState]](None) 18 | with VDomLens[Context, Option[VDomState]] 19 | 20 | 21 | trait ViewRestPeriodProvider { 22 | def get(local: Context): ViewRestPeriod 23 | } 24 | 25 | sealed trait ViewRestPeriod extends Product { 26 | def valueMillis: Long 27 | } 28 | 29 | case class DynamicViewRestPeriod(valueMillis: Long) extends ViewRestPeriod 30 | case class StaticViewRestPeriod(valueMillis: Long) extends ViewRestPeriod 31 | 32 | case object ViewRestPeriodKey extends TransientLens[Option[ViewRestPeriod]](None) 33 | 34 | trait ViewFailed { 35 | def of(local: Context): Boolean 36 | } 37 | 38 | trait VDomUntil { 39 | def get(seeds: Seq[BranchResult]): Long 40 | } 41 | 42 | trait FromAlienTask extends Product { 43 | def branchKey: SrcId 44 | def branchTask: BranchTask 45 | def userName: String 46 | def fromAlienState: U_FromAlienState 47 | def locationQuery: String 48 | def locationHash: String 49 | } 50 | 51 | case object CurrentBranchKey extends TransientLens[SrcId]("") 52 | 53 | trait UpdatingReceiverFactory { 54 | def create(updater: Updater, action: VAction): Receiver[Context] 55 | } 56 | trait Updater extends Product { 57 | type Handler = String => Context => VAction => TxEvents 58 | def receive: Handler 59 | def rc: UpdatingReceiverFactory 60 | def rc(action: VAction): Receiver[Context] = rc.create(this, action) 61 | } 62 | trait VAction extends Product -------------------------------------------------------------------------------- /perl_script_relations.txt: -------------------------------------------------------------------------------- 1 | 2 | some dockerfile -> install.pl 3 | builder dockerfile -> prod.pl ci_* -> build.pl, bloop_fix.pl 4 | 5 | prod.pl bakes install.pl to many images 6 | prod.pl bakes cd.pl to corresponding image 7 | prod.pl bakes sandbox.pl,prod.pl to developing image 8 | prod.pl bakes run.pl to prod image 9 | 10 | manual -> prod.pl 11 | 12 | only manual => app.pl 13 | app.pl -> sync.pl 14 | app.pl -> build.pl 15 | 16 | manual -> do.pl 17 | 18 | serve.pl: 19 | -> prod.pl need_certs 20 | -> do.pl run 21 | -> build.pl 22 | 23 | ######################################################################################################################## 24 | 25 | 26 | test_env.py was -- from j_a 27 | 28 | build.py -- initial generate sbt etc 29 | from: l4, dev_server, prod.pl 30 | 31 | build_env.py -- get paths of what was built 32 | from: do.pl, dev_server, prod/ci_rt_over, sandbox.pl 33 | 34 | 35 | build_remote.py/ci_prep -- from ci_prep.py 36 | build_remote.py/compile -- from sandbox.pl 37 | build_remote.py/build_inner -- self 38 | 39 | ceph.pl -- from: sandbox.pl, run.pl 40 | 41 | chk_pkg_dep.py -- from prod.pl 42 | 43 | ci.py -- purge_* -- from prod.pl 44 | 45 | ci_prep.py -- c4ci_prep -- from: manual, gitlab.py 46 | ci_up.py -- c4ci_up -- from: manual, gitlab.py 47 | 48 | do.pl -- manual tests 49 | 50 | gitlab.py -- from gitlab 51 | gitlab-gen.py -- from l4 52 | 53 | kube_reporter.py -- server 54 | 55 | make_manifests.pl -- from build_remote.py/ci_prep 56 | 57 | prod.pl 58 | manual 59 | ci_deploy_info, build_client, ci_rt_* -- from build_remote.py 60 | build_client -- from sandbox.pl 61 | 62 | resources.py -- from: prod.pl, server 63 | run.pl -- server 64 | 65 | run_with_prefix.py -- from build_remote.py 66 | 67 | sandbox.pl -- server 68 | 69 | sync.pl -- from: sync_client.pl, dev_server, L4 70 | 71 | sync.py -- c4py -- from sync.bat -- seems not used 72 | 73 | sync_mem.pl -- from build_remote.py/ci_prep 74 | 75 | sync_setup.pl -- from: build_remote.py, agent 76 | 77 | vault.py -- from: sandbox.pl, run.pl 78 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4actor/sandbox/SanboxLensTutuorial.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4actor.sandbox 2 | 3 | import ee.cone.c4actor.{Lens, NameMetaAttr, ProdLens} 4 | import ee.cone.c4assemble.Getter 5 | 6 | object SanboxLensTutuorial { 7 | def main(args: Array[String]): Unit = { 8 | 9 | val person = D_Person("Dmitri", Phone(123, (789, 75, 99))) 10 | val number = person.phone.number._3 11 | person.copy( 12 | phone = person.phone.copy( 13 | number = person.phone.number.copy( 14 | _3 = 88 15 | ) 16 | ) 17 | ) 18 | 19 | val newPerson = PersonToPhoneLens.set(Phone(1, (1, 2, 3)))(person) 20 | 21 | /* 22 | val prodPhoneLens: ProdLens[D_Person, Phone] = 23 | ProdLens.ofS et[D_Person, Phone]( 24 | _.phone, 25 | phone => _.copy(phone = phone), 26 | "PersonToPhone" 27 | ) 28 | val prodCodeLens: ProdLens[Phone, Int] = 29 | ProdLens.of Set[Phone, Int]( 30 | _.code, 31 | code => _.copy(code = code), 32 | "PhoneToCode" 33 | ) 34 | val prodPersonCodeLens: ProdLens[D_Person, Int] = 35 | prodPhoneLens.to(prodCodeLens) 36 | 37 | */ 38 | 39 | println(); 40 | } 41 | } 42 | 43 | case class Phone(code: Int, number: (Int, Int, Int)) 44 | 45 | case class D_Person(name: String, phone: Phone) 46 | 47 | trait PhoneGetter extends Getter[D_Person, Phone] { 48 | def of: D_Person => Phone = _.phone 49 | } 50 | 51 | case object CodeGetter extends Getter[Phone, Int] { 52 | def of: Phone => Int = _.code 53 | } 54 | 55 | case class GetterComposer[A, B, C](getterA: Getter[A, B], getterB: Getter[B, C]) extends Getter[A, C] { 56 | def of: A => C = model => getterB.of(getterA.of(model)) 57 | } 58 | 59 | case object PersonToPhoneLens extends Lens[D_Person, Phone] 60 | with PhoneGetter { 61 | def modify: (Phone => Phone) => D_Person => D_Person = 62 | f => model => set(f(of(model)))(model) 63 | 64 | def set: Phone => D_Person => D_Person = 65 | newPhone => _.copy(phone = newPhone) 66 | } 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /extra_examples/src/main/scala/ee/cone/c4ui/FailOverTest.scala: -------------------------------------------------------------------------------- 1 | package ee.cone.c4ui 2 | 3 | import com.typesafe.scalalogging.LazyLogging 4 | import ee.cone.c4actor._ 5 | import ee.cone.c4actor.QProtocol.S_Firstborn 6 | import ee.cone.c4actor.Types.SrcId 7 | import ee.cone.c4assemble.c4assemble 8 | import ee.cone.c4assemble.Types._ 9 | import ee.cone.c4di._ 10 | import scala.annotation.tailrec 11 | 12 | /* 13 | @c4("TestTodoApp") final class FailOverTest( 14 | config: Config, 15 | actorName: ActorName, 16 | execution: Execution, 17 | ) extends Executable with LazyLogging { 18 | def run(): Unit = concurrent.blocking { 19 | val remove = execution.onShutdown("test-fail-over",()=>{ 20 | iter(true) 21 | }) 22 | iter(false) 23 | } 24 | @tailrec def iter(isFinal: Boolean): Unit = { 25 | logger.debug(s"normal ${actorName.value} ${config.get("C4ELECTOR_SERVERS")}") 26 | Thread.sleep(100) 27 | iter(isFinal) 28 | } 29 | } 30 | */ 31 | 32 | /* 33 | @c4("TestTodoApp") final class FailOverTestEnable 34 | extends EnableSimpleScaling(classOf[FailOverTestTx]) 35 | 36 | @c4("TestTodoApp") final class FailOverTest extends Executable with LazyLogging { 37 | def run(): Unit = iter() 38 | @tailrec def iter(): Unit = { 39 | logger.debug(s"Executable up") 40 | Thread.sleep(100) 41 | iter() 42 | } 43 | } 44 | 45 | @c4assemble("TestTodoApp") class FailOverTestAssembleBase( 46 | failOverTestTxFactory: FailOverTestTxFactory 47 | ){ 48 | def toTx( 49 | srcId: SrcId, 50 | firstborn: Each[S_Firstborn], 51 | ): Values[(SrcId, TxTransform)] = 52 | List( 53 | WithPK(failOverTestTxFactory.create("FailOverTest-0")), 54 | WithPK(failOverTestTxFactory.create("FailOverTest-1")), 55 | WithPK(failOverTestTxFactory.create("FailOverTest-2")), 56 | ) 57 | } 58 | 59 | @c4multi("TestTodoApp") final case class FailOverTestTx( 60 | srcId: SrcId 61 | ) extends TxTransform with LazyLogging { 62 | def transform(local: Context): Context = { 63 | logger.debug(s"Tx up $srcId") 64 | local 65 | } 66 | }*/ --------------------------------------------------------------------------------