locality_social_cloud 1.2.0 locality_social_cloud: ^1.2.0 copied to clipboard
Write social apps with Flutter. This code connects to the backend of Locality Social Cloud to provide realtime state synchronization across devices.
locality_social_cloud #
Build Social Networks #
Locality is there to fuel the development of Social Networks with Flutter. We identified crucial patterns of social media apps to allow you to build serverless social networks with seamless realtime interactions, like group-stories, friends, chats, events, game states and whatever you may come up with. Locality Social Cloud provides you with a PubSub mixin that allows you to publish to and receive events from addresses in realtime. You are provided with the guarantee, that each PubSub processes each event that was published to its address exactly once. This holds true, even if the user goes offline or loses connection; once he is online again, the state is seamlessly synchronized. In addition to this, Locality Social Cloud allows you to easily build End-to-End-Encryption; Each user has a public ECDH key and you have methods of generating a shared key and encrypting PubSubs with keys. On top of that, users can securely share keys accross devices and yield keys for end-to-end-encrypted topics, so that you can, for example, write encrypted group chats.
Social Spaces #
Social Apps are fundamentally a technological reflection of real social interactions. In real social interactions, we interact through objective space that transports state changes at light speed. The challenge of creating objective spaces for multiple observers across many devices is fundamental. In order to model the observed state of a logical group of data consistently, it is neccessary to model the current state as the result of a sequence of order-agnostic transformations from an initial state. Order-agnostic in this sense means: The state you compute should be invariant against permutation of the sequence in which state changes are applied. Traditionally, state management and business logic are performed on servers. This creates significant challenges when dealing with End-to-End-encrypted interactions. With Locality Social Cloud we provide a novel framework of creating objective spaces for many different observers across many different devices with frontend-driven state management. We solve for you hard problems like partial system failures (users going offline), uptime guarantees and caching and provide you with a seamless way for managing state across all of your applications.
Project Setup #
Create a developer account for your company #
First, register a developer account and an app. You can do that here.
Add the locality_social_cloud library to Flutter #
Write
flutter pub add locality_social_cloud
flutter pub get
to add the Locality Social Cloud to your Flutter App.
Configure Locality Social Cloud #
Obtain your app-ID and app secret from your developer account and write
LocalitySocialCloud.configure(app_id: 'YOUR APP ID', app_secret: 'YOUR APP SECRET');
to set up your social cloud.
Example #
Create a controller #
class ExampleController extends ChangeNotifier with PubSub {
int counter = 0;
@override
String getTopic() {
return 'global-click-counter2';
}
void increaseCounter(int amount) {
send('increaseCounter', {
'amount': amount
});
}
@override
void onReceive(LocalityEvent localityEvent) {
switch(localityEvent.event) {
case 'increaseCounter':
counter += localityEvent.payload['amount'] as int;
print("CLICK COUNTER IS AT "+counter.toString());
notifyListeners();
break;
}
}
}
Create a view for your controller #
class CounterView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final exampleController = ExampleController();
return ChangeNotifierProvider.value(
value: exampleController,
child: Scaffold(
appBar: AppBar(
title: Text('Click Counter'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Consumer<ExampleController>(
builder: (context, exampleController, child) {
return Text(
'${exampleController.counter}',
style: Theme.of(context).textTheme.headline4,
);
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
exampleController.increaseCounter(1);
},
child: Text('Increment Counter'),
),
],
),
),
),
);
}
}
Connect to the Social Cloud #
LocalitySocialCloud.configure(app_id: 'Locality App', app_secret: '6mSgwtp85n7BQA5c6dcDsioMwuH6AHWtYBICpkdZvN4=');
LoggedInUserOrError userOrError = await Auth.login("123", "pwd");LoggedInUser? loggedInUser = await Auth.login("test_user1235", "pwd");
if ( userOrError.isUser() ) {
LocalitySocialCloud.connect(userOrError.getUser());
controllerExample(userOrError.getUser());
} else {
print("ERROR: "+loggedInUserOrError.authError.toString());
}
LocalitySocialCloud.connect(userOrError!);
End-to-End encryption #
Locality Social Cloud provides End-to-End-Encryption based on ECDH M-511, Sha256 and ChaCha20.
Common key for users #
loggedInUser.getKeyFor(otherLoggedInUser);
Secure a topic #
You can also encrypt groups. Each topic belongs to the user who registered it first. Each key is available on each device of the user. You must send the key to another user via direct-message in order to let him or her participate in a group.
void authExample(LoggedInUser loggedInUser) async
{
TopicAuth topicAuth = LocalitySocialCloud.loadTopicAuths(loggedInUser);
topicAuth.secureChannel(
channel: 'globally-unique-topic-id',
secret: 'generated_secret_password',
metadata: {
'profile_img': 'https://...',
'groupname': 'New Chatgroup',
'role': 'Administrator'
}
);
topicAuth.addListener(() {
print("LISTING ALL SECURE CHANNELS: ");
topicAuth.secureChannels.forEach((element) {
print("SECURE CHANNEL "+element.toString());
});
});
}
Discover users #
By Username #
DiscoverUsers discoverUsers = LocalitySocialCloud.discoverUsers();
discoverUsers.startingWith('Maltii');
discoverUsers.addListener(() {
print("WE DISCOVERED SOME USERS!");
discoverUsers.discoveredUsers.forEach((user) {
print("WE DISCOVERED: "+user.id);
});
});
By proximity #
Below is an example of a GeoChannel. You are assigned a session id in the background. Whenever you ping a location, your location gets updated. A session has a standard lifetime of 30 seconds that gets refreshed at every update via pingLocation. You can discover other entities on the same GeoChannel with getNearbyEntities. This will also return the metadata.
GeoChannel geoIndex = GeoChannel('nearby-people', metadata: "Hello!!");
geoIndex.connect(PubSubSupervisor.supervisor);
Timer.periodic(Duration(milliseconds: 5000), (timer) {
geoIndex.pingLocation(
latitude: 90.7128+math.Random().nextDouble()*10,
longitude: -74.0060+math.Random().nextDouble()*10
);
geoIndex.getNearbyEntities(90.71, -74.006, 1).then((value){
print(value.toString());
});
});
Cache #
The cache is based on SQlite. Thus, on windows, you have to use
databaseFactory = databaseFactoryFfi;
sqfliteFfiInit();
You set a cache by calling
PubSubSupervisor.cache = Cache(await MessageRepository.getInstance());
Wrapup #
Locality Social Cloud offers powerful tools for Flutter Developers to enhance their social apps. Once you get used to modeling your data as sequences of abelian state diffs, your mind will finally be at peace with state management.